diff --git a/.github/.cSpellWords.txt b/.github/.cSpellWords.txt
index fefedc5b5..9b007225b 100644
--- a/.github/.cSpellWords.txt
+++ b/.github/.cSpellWords.txt
@@ -28,6 +28,10 @@ misra
Misra
MISRA
MQTT
+mqttpropadd
+mqttpropertybuilder
+mqttpropget
+MQTTV
mypy
nondet
Nondet
@@ -37,6 +41,7 @@ pytest
pyyaml
serializemqttvec
sinclude
+subscriptionid
UNACKED
unpadded
Unpadded
diff --git a/.github/memory_statistics_config.json b/.github/memory_statistics_config.json
index b7969774c..717f6bd28 100644
--- a/.github/memory_statistics_config.json
+++ b/.github/memory_statistics_config.json
@@ -3,10 +3,14 @@
"src": [
"source/core_mqtt.c",
"source/core_mqtt_state.c",
- "source/core_mqtt_serializer.c"
+ "source/core_mqtt_serializer.c",
+ "source/core_mqtt_serializer_private.c",
+ "source/core_mqtt_prop_serializer.c",
+ "source/core_mqtt_prop_deserializer.c"
],
"include": [
"source/include",
+ "source/include/private",
"source/interface"
],
"compiler_flags": [
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3be05166d..cdfc45cec 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,7 +10,7 @@ on:
push:
branches: ["**"]
pull_request:
- branches: [main]
+ branches: [main, MQTTv5-reviewed-changes]
workflow_dispatch:
jobs:
@@ -83,6 +83,7 @@ jobs:
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
with:
coverage-file: ./build/coverage.info
+ branch-coverage-min: 94
complexity:
runs-on: ubuntu-latest
@@ -154,6 +155,7 @@ jobs:
mkdir -p override-include
cp source/include/stdbool.readme override-include/stdbool.h
cp source/include/stdint.readme override-include/stdint.h
+ cp source/include/inttypes.readme override-include/inttypes.h
# Build using the custom headers
cmake -S test -B build/ \
diff --git a/docs/doxygen/config.doxyfile b/docs/doxygen/config.doxyfile
index ca0047ec4..ca9402cc3 100644
--- a/docs/doxygen/config.doxyfile
+++ b/docs/doxygen/config.doxyfile
@@ -54,7 +54,7 @@ PROJECT_NUMBER = v2.3.1+
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF = "MQTT 3.1.1 Client Library"
+PROJECT_BRIEF = "MQTT 5.0 Client Library"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@@ -923,6 +923,7 @@ WARN_LOGFILE =
INPUT = ./docs/doxygen \
./source/include \
+ ./source/include/private \
./source/interface \
./source
diff --git a/docs/doxygen/include/size_table.md b/docs/doxygen/include/size_table.md
index 5f654632f..a7e7a14e2 100644
--- a/docs/doxygen/include/size_table.md
+++ b/docs/doxygen/include/size_table.md
@@ -9,8 +9,8 @@
| core_mqtt.c |
- 4.9K |
- 4.2K |
+ 8.1K |
+ 7.0K |
| core_mqtt_state.c |
@@ -19,12 +19,27 @@
| core_mqtt_serializer.c |
- 2.9K |
- 2.3K |
+ 9.2K |
+ 7.4K |
+
+
+ | core_mqtt_serializer_private.c |
+ 0.8K |
+ 0.7K |
+
+
+ | core_mqtt_prop_serializer.c |
+ 1.6K |
+ 1.3K |
+
+
+ | core_mqtt_prop_deserializer.c |
+ 1.3K |
+ 1.0K |
| Total estimates |
- 9.5K |
- 7.8K |
+ 22.7K |
+ 18.7K |
diff --git a/docs/doxygen/pages.dox b/docs/doxygen/pages.dox
index 750df5336..e21102f52 100644
--- a/docs/doxygen/pages.dox
+++ b/docs/doxygen/pages.dox
@@ -1,12 +1,12 @@
/**
@mainpage Overview
@anchor mqtt
-@brief MQTT 3.1.1 client library
+@brief MQTT 5.0 client library
> MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. The design principles are to minimise network bandwidth and device resource requirements whilst also attempting to ensure reliability and some degree of assurance of delivery. These principles also turn out to make the protocol ideal of the emerging "machine-to-machine" (M2M) or "Internet of Things" world of connected devices, and for mobile applications where bandwidth and battery power are at a premium.
— Official description of MQTT from [mqtt.org](https://mqtt.org)
-This MQTT library implements the client side of the MQTT 3.1.1 protocol. This library is optimized for resource constrained embedded devices. Features of this library include:
+This MQTT library implements the client side of the MQTT 5.0 protocol. This library is optimized for resource constrained embedded devices. Features of this library include:
- Fully synchronous API, to allow applications to completely manage their concurrency and multi-threading method.
- Operations on fixed buffers, so that applications may control their memory allocation strategy.
- Scalable performance and footprint. The [configuration settings](@ref core_mqtt_config) allow this library to be tailored to a system's resources.
@@ -23,7 +23,7 @@ Please see https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/
@page mqtt_design Design
@brief Architecture of the MQTT library.
-This MQTT client library provides an implementation of the [MQTT 3.1.1 specification](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html). It is optimized for resource constrained devices and does not allocate any memory.
+This MQTT client library provides an implementation of the [MQTT 5.0 specification](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html). It is optimized for resource constrained devices and does not allocate any memory.
@section mqtt_interfaces Interfaces and Callbacks
@@ -56,6 +56,28 @@ The MQTT library expects the application to provide implementations for the foll
+Apart from these, users can optionally define the following callbacks if they wish to use library's mechanism to resend
+unacknowledged publish packets on a persistent session reconnection.
+
+
+
+ | Function Pointer |
+ Use |
+
+
+ | @ref MQTTStorePacketForRetransmit |
+ Storing an outgoing publish packet. |
+
+
+ | @ref MQTTRetrievePacketForRetransmit |
+ Retreiving the stored publish packet for retransmission. |
+
+
+ | @ref MQTTClearPacketForRetransmit |
+ Removing the stored copy of a publish packet |
+
+
+
@section mqtt_serializers Serializers and Deserializers
The managed MQTT API in @ref core_mqtt.h uses a set of serialization and deserialization functions
@@ -66,33 +88,40 @@ these low-level functions can be used directly:
- @ref mqtt_serializeconnect_function
- @ref mqtt_getsubscribepacketsize_function
- @ref mqtt_serializesubscribe_function
+- @ref mqtt_validatesubscribeproperties_function
- @ref mqtt_getunsubscribepacketsize_function
- @ref mqtt_serializeunsubscribe_function
- @ref mqtt_getpublishpacketsize_function
- @ref mqtt_serializepublish_function
- @ref mqtt_serializepublishheader_function
+- @ref mqtt_serializepublishheaderwithouttopic_function
+- @ref mqtt_validatepublishparams_function
+- @ref mqtt_validatepublishproperties_function
- @ref mqtt_serializeack_function
+- @ref mqtt_getackpacketsize_function
- @ref mqtt_getdisconnectpacketsize_function
-- @ref mqtt_serializedisconnect_function
- @ref mqtt_getpingreqpacketsize_function
- @ref mqtt_serializepingreq_function
- @ref mqtt_deserializepublish_function
- @ref mqtt_deserializeack_function
- @ref mqtt_getincomingpackettypeandlength_function
+- @ref mqtt_initconnect_function
@section mqtt_sessions Sessions and State
-The MQTT 3.1.1 protocol allows for a client and server to maintain persistent sessions, which
+The MQTT 5.0 protocol allows for a client and server to maintain persistent sessions, which
can be resumed after a reconnect. The elements of a session stored by this client library consist
of the states of incomplete publishes with Quality of Service levels of 1 (at least once), or 2 (exactly once).
These states are stored in the pointers pointed to by @ref MQTTContext_t.outgoingPublishRecords and @ref MQTTContext_t.incomingPublishRecords;
This library does not store any subscription information, nor any information for QoS 0 publishes.
When resuming a persistent session, the client library will resend PUBRELs for all PUBRECs that had been received
-for incomplete outgoing QoS 2 publishes. If the broker does not resume the session, then all state information
+for incomplete outgoing QoS 2 publishes. If the optional retransmission callbacks are defined then the library will also
+resend any unacknowledged QoS>0 publishes. If the broker does not resume the session, then all state information
in the client will be reset.
-@note The library stores only the state of incomplete publishes and not the publish payloads. It is the responsibility of the user application to save publish payloads until the publish is complete.
+@note The library stores only the state of incomplete publishes and not the publish payloads. If the retransmission
+callbacks are not defined then, it is the responsibility of the user application to save publish payloads until the publish is complete.
If a persistent session is resumed, then @ref mqtt_publishtoresend_function should be called to obtain the
packet identifiers of incomplete publishes, followed by a call to @ref mqtt_publish_function to resend the
unacknowledged publish.
@@ -107,14 +136,13 @@ The exception is @ref mqtt_connect_function; since a MQTT session cannot be cons
the function waits until the CONNACK is received.
@subsection mqtt_receivetimeout Runtime Timeouts passed to MQTT library
-@ref mqtt_connect_function, @ref mqtt_processloop_function, and @ref mqtt_receiveloop_function all accept a timeout parameter for packet reception.
-For the @ref mqtt_connect_function, if this value is set to 0, then instead of a time-based loop, it will attempt to call the transport receive function up to a maximum number of retries,
+@ref mqtt_connect_function accepts a timeout parameter for packet reception. If this value is set to 0, then instead of a time-based loop, it will attempt to call the transport receive function up to a maximum number of retries,
which is defined by @ref MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT.
-For @ref mqtt_processloop_function and @ref mqtt_receiveloop_function, the timeout value represents the minimum duration that will be spent in the function, provided there are no network errors.
-Should the timeout be set to 0, then the loop will run for a single iteration. A single iteration of a loop consists of an attempt to receive a single byte from the network, and
-if the single byte receive was successful, then attempt(s) to receive the rest of the packet (with retry attempts governed by @ref MQTT_RECV_POLLING_TIMEOUT_MS), followed by sending acknowledgement response, if needed
-(with retry attempts governed by @ref MQTT_SEND_TIMEOUT_MS), and then, finally deserialization of the packet received and a call to the application callback.
+For @ref mqtt_processloop_function and @ref mqtt_receiveloop_function, the timeout functionality is handled by the user application. It is up to the user to define the number of times these functions will be called, provided that there are no network errors.
+A single call to the function consists of an attempt to receive all available bytes from the network. If the read was successful, attempt(s) to receive the rest of the packet (with retry attempts governed by @ref MQTT_RECV_POLLING_TIMEOUT_MS) are made.
+This is followed by the deserialization of the received packet. After this a the application callback is invoked, followed by sending acknowledgement response, if needed
+(with retry attempts governed by @ref MQTT_SEND_TIMEOUT_MS).
If the first read did not succeed, then instead the library checks if a ping request needs to be sent (only for the process loop).
See the below diagrams for a representation of the above flows:
@@ -127,7 +155,8 @@ See the below diagrams for a representation of the above flows:
The MQTT standard specifies a keep-alive mechanism to detect half-open or otherwise unusable network connections.
An MQTT client will send periodic ping requests (PINGREQ) to the server if the connection is idle. The MQTT server must respond to ping requests with a ping response (PINGRESP).
-In this library, @ref mqtt_processloop_function handles sending of PINGREQs and processing corresponding PINGRESPs to comply with the keep-alive interval set in @ref MQTTContext_t.keepAliveIntervalSec.
+In this library, @ref mqtt_processloop_function handles sending of PINGREQs and processing corresponding PINGRESPs to comply with the keep-alive interval. The value of the keep alive interval is the one set in @ref MQTTContext_t.keepAliveIntervalSec
+unless the server had sent a Server Keep Alive property in the CONNACK packet, in which case the Server Keep Alive value will be used.
The standard does not specify the time duration within which the server has to respond to a ping request, noting only a "reasonable amount of time". If the response to a ping request is not received within @ref MQTT_PINGRESP_TIMEOUT_MS, this library assumes that the connection is dead.
@@ -175,8 +204,16 @@ Some configuration settings are C pre-processor constants, and some are function
/**
@page mqtt_functions Functions
-@brief Primary functions of the MQTT library:
+@brief The functions of the MQTT Library are categorised as follows
+- @subpage mqtt_primaryfunctions
+- @subpage mqtt_serializerfunctions
+- @subpage mqtt_propertyaddfunctions
+- @subpage mqtt_propertygetfunctions
+
+@page mqtt_primaryfunctions Primary functions
@subpage mqtt_init_function
+@subpage mqtt_initstatefulqos_function
+@subpage mqtt_initretransmits_function
@subpage mqtt_connect_function
@subpage mqtt_subscribe_function
@subpage mqtt_publish_function
@@ -190,29 +227,79 @@ Some configuration settings are C pre-processor constants, and some are function
@subpage mqtt_status_strerror_function
@subpage mqtt_publishtoresend_function
-Serializer functions of the MQTT library:
+@page mqtt_serializerfunctions Serializer functions
+@subpage mqttpropertybuilder_init_function
@subpage mqtt_getconnectpacketsize_function
@subpage mqtt_serializeconnect_function
@subpage mqtt_getsubscribepacketsize_function
@subpage mqtt_serializesubscribe_function
+@subpage mqtt_validatesubscribeproperties_function
@subpage mqtt_getunsubscribepacketsize_function
@subpage mqtt_serializeunsubscribe_function
@subpage mqtt_getpublishpacketsize_function
@subpage mqtt_serializepublish_function
@subpage mqtt_serializepublishheader_function
+@subpage mqtt_serializepublishheaderwithouttopic_function
+@subpage mqtt_validatepublishparams_function
+@subpage mqtt_validatepublishproperties_function
@subpage mqtt_serializeack_function
+@subpage mqtt_getackpacketsize_function
@subpage mqtt_getdisconnectpacketsize_function
-@subpage mqtt_serializedisconnect_function
@subpage mqtt_getpingreqpacketsize_function
@subpage mqtt_serializepingreq_function
@subpage mqtt_deserializepublish_function
@subpage mqtt_deserializeack_function
@subpage mqtt_getincomingpackettypeandlength_function
+@subpage mqtt_initconnect_function
+
+@page mqtt_propertyaddfunctions Property Add functions
+@subpage mqttpropadd_subscriptionid_function
+@subpage mqttpropadd_userprop_function
+@subpage mqttpropadd_sessionexpiry_function
+@subpage mqttpropadd_connreceivemax_function
+@subpage mqttpropadd_connmaxpacketsize_function
+@subpage mqttpropadd_conntopicaliasmax_function
+@subpage mqttpropadd_connrequestrespinfo_function
+@subpage mqttpropadd_connrequestprobinfo_function
+@subpage mqttpropadd_connauthmethod_function
+@subpage mqttpropadd_connauthdata_function
+@subpage mqttpropadd_willdelayinterval_function
+@subpage mqttpropadd_pubpayloadformat_function
+@subpage mqttpropadd_pubmessageexpiry_function
+@subpage mqttpropadd_pubtopicalias_function
+@subpage mqttpropadd_pubresponsetopic_function
+@subpage mqttpropadd_pubcorrelationdata_function
+@subpage mqttpropadd_pubcontenttype_function
+@subpage mqttpropadd_reasonstring_function
+
+@page mqtt_propertygetfunctions Property Get functions
+@subpage MQTTPropGet_payloadformat_function
+@subpage MQTTPropGet_responsetopic_function
+@subpage MQTTPropGet_correlationdata_function
+@subpage MQTTPropGet_messageexpiryinterval_function
+@subpage MQTTPropGet_contenttype_function
+@subpage MQTTPropGet_subscriptionid_function
+@subpage mqttpropget_userprop_function
+@subpage mqttpropget_reasonstring_function
+@subpage mqttpropget_sessionexpiry_function
+@subpage MQTTPropGet_topicaliasmax_function
+@subpage MQTTPropGet_receivemax_function
+@subpage MQTTPropGet_maxqos_function
+@subpage MQTTPropGet_retainavailable_function
+@subpage MQTTPropGet_maxpacketsize_function
@page mqtt_init_function MQTT_Init
@snippet core_mqtt.h declare_mqtt_init
@copydoc MQTT_Init
+@page mqtt_initstatefulqos_function MQTT_InitStatefulQoS
+@snippet core_mqtt.h declare_mqtt_initstatefulqos
+@copydoc MQTT_InitStatefulQoS
+
+@page mqtt_initretransmits_function MQTT_InitRetransmits
+@snippet core_mqtt.h declare_mqtt_initretransmits
+@copydoc MQTT_InitRetransmits
+
@page mqtt_connect_function MQTT_Connect
@snippet core_mqtt.h declare_mqtt_connect
@copydoc MQTT_Connect
@@ -261,6 +348,10 @@ Serializer functions of the MQTT library:
@snippet core_mqtt_state.h declare_mqtt_publishtoresend
@copydoc MQTT_PublishToResend
+@page mqttpropertybuilder_init_function MQTTPropertyBuilder_Init
+@snippet core_mqtt_serializer.h declare_mqttpropertybuilder_init
+@copydoc MQTTPropertyBuilder_Init
+
@page mqtt_getconnectpacketsize_function MQTT_GetConnectPacketSize
@snippet core_mqtt_serializer.h declare_mqtt_getconnectpacketsize
@copydoc MQTT_GetConnectPacketSize
@@ -285,6 +376,10 @@ Serializer functions of the MQTT library:
@snippet core_mqtt_serializer.h declare_mqtt_serializeunsubscribe
@copydoc MQTT_SerializeUnsubscribe
+@page mqtt_validatepublishparams_function MQTT_ValidatePublishParams
+@snippet core_mqtt_serializer.h declare_mqtt_validatepublishparams
+@copydoc MQTT_ValidatePublishParams
+
@page mqtt_getpublishpacketsize_function MQTT_GetPublishPacketSize
@snippet core_mqtt_serializer.h declare_mqtt_getpublishpacketsize
@copydoc MQTT_GetPublishPacketSize
@@ -293,22 +388,30 @@ Serializer functions of the MQTT library:
@snippet core_mqtt_serializer.h declare_mqtt_serializepublish
@copydoc MQTT_SerializePublish
+@page mqtt_validatepublishproperties_function MQTT_ValidatePublishProperties
+@snippet core_mqtt_serializer.h declare_mqtt_validatepublishproperties
+@copydoc MQTT_ValidatePublishProperties
+
@page mqtt_serializepublishheader_function MQTT_SerializePublishHeader
@snippet core_mqtt_serializer.h declare_mqtt_serializepublishheader
@copydoc MQTT_SerializePublishHeader
+@page mqtt_serializepublishheaderwithouttopic_function MQTT_SerializePublishHeaderWithoutTopic
+@snippet core_mqtt_serializer.h declare_mqtt_serializepublishheaderwithouttopic
+@copydoc MQTT_SerializePublishHeaderWithoutTopic
+
@page mqtt_serializeack_function MQTT_SerializeAck
@snippet core_mqtt_serializer.h declare_mqtt_serializeack
@copydoc MQTT_SerializeAck
+@page mqtt_getackpacketsize_function MQTT_GetAckPacketSize
+@snippet core_mqtt_serializer.h declare_mqtt_getackpacketsize
+@copydoc MQTT_GetAckPacketSize
+
@page mqtt_getdisconnectpacketsize_function MQTT_GetDisconnectPacketSize
@snippet core_mqtt_serializer.h declare_mqtt_getdisconnectpacketsize
@copydoc MQTT_GetDisconnectPacketSize
-@page mqtt_serializedisconnect_function MQTT_SerializeDisconnect
-@snippet core_mqtt_serializer.h declare_mqtt_serializedisconnect
-@copydoc MQTT_SerializeDisconnect
-
@page mqtt_getpingreqpacketsize_function MQTT_GetPingreqPacketSize
@snippet core_mqtt_serializer.h declare_mqtt_getpingreqpacketsize
@copydoc MQTT_GetPingreqPacketSize
@@ -328,6 +431,147 @@ Serializer functions of the MQTT library:
@page mqtt_getincomingpackettypeandlength_function MQTT_GetIncomingPacketTypeAndLength
@snippet core_mqtt_serializer.h declare_mqtt_getincomingpackettypeandlength
@copydoc MQTT_GetIncomingPacketTypeAndLength
+
+@page mqttpropadd_subscriptionid_function MQTTPropAdd_SubscriptionId
+@snippet core_mqtt_serializer.h declare_mqttpropadd_subscriptionid
+@copydoc MQTTPropAdd_SubscriptionId
+
+@page mqttpropadd_userprop_function MQTTPropAdd_UserProp
+@snippet core_mqtt_serializer.h declare_mqttpropadd_userprop
+@copydoc MQTTPropAdd_UserProp
+
+@page mqttpropadd_sessionexpiry_function MQTTPropAdd_SessionExpiry
+@snippet core_mqtt_serializer.h declare_mqttpropadd_sessionexpiry
+@copydoc MQTTPropAdd_SessionExpiry
+
+@page mqttpropadd_willdelayinterval_function MQTTPropAdd_WillDelayInterval
+@snippet core_mqtt_serializer.h declare_mqttpropadd_willdelayinterval
+@copydoc MQTTPropAdd_WillDelayInterval
+
+@page mqttpropadd_connreceivemax_function MQTTPropAdd_ReceiveMax
+@snippet core_mqtt_serializer.h declare_mqttpropadd_receivemax
+@copydoc MQTTPropAdd_ReceiveMax
+
+@page mqttpropadd_connmaxpacketsize_function MQTTPropAdd_MaxPacketSize
+@snippet core_mqtt_serializer.h declare_mqttpropadd_maxpacketsize
+@copydoc MQTTPropAdd_MaxPacketSize
+
+@page mqttpropadd_conntopicaliasmax_function MQTTPropAdd_TopicAliasMax
+@snippet core_mqtt_serializer.h declare_mqttpropadd_topicaliasmax
+@copydoc MQTTPropAdd_TopicAliasMax
+
+@page mqttpropadd_connrequestrespinfo_function MQTTPropAdd_RequestRespInfo
+@snippet core_mqtt_serializer.h declare_mqttpropadd_requestrespinfo
+@copydoc MQTTPropAdd_RequestRespInfo
+
+@page mqttpropadd_connrequestprobinfo_function MQTTPropAdd_RequestProbInfo
+@snippet core_mqtt_serializer.h declare_mqttpropadd_requestprobinfo
+@copydoc MQTTPropAdd_RequestProbInfo
+
+@page mqttpropadd_connauthmethod_function MQTTPropAdd_AuthMethod
+@snippet core_mqtt_serializer.h declare_mqttpropadd_authmethod
+@copydoc MQTTPropAdd_AuthMethod
+
+@page mqttpropadd_connauthdata_function MQTTPropAdd_AuthData
+@snippet core_mqtt_serializer.h declare_mqttpropadd_authdata
+@copydoc MQTTPropAdd_AuthData
+
+@page mqttpropadd_pubpayloadformat_function MQTTPropAdd_PayloadFormat
+@snippet core_mqtt_serializer.h declare_mqttpropadd_payloadformat
+@copydoc MQTTPropAdd_PayloadFormat
+
+@page mqttpropadd_pubmessageexpiry_function MQTTPropAdd_MessageExpiry
+@snippet core_mqtt_serializer.h declare_mqttpropadd_messageexpiry
+@copydoc MQTTPropAdd_MessageExpiry
+
+@page mqttpropadd_pubtopicalias_function MQTTPropAdd_TopicAlias
+@snippet core_mqtt_serializer.h declare_mqttpropadd_topicalias
+@copydoc MQTTPropAdd_TopicAlias
+
+@page mqttpropadd_pubresponsetopic_function MQTTPropAdd_ResponseTopic
+@snippet core_mqtt_serializer.h declare_mqttpropadd_responsetopic
+@copydoc MQTTPropAdd_ResponseTopic
+
+@page mqttpropadd_pubcorrelationdata_function MQTTPropAdd_CorrelationData
+@snippet core_mqtt_serializer.h declare_mqttpropadd_correlationdata
+@copydoc MQTTPropAdd_CorrelationData
+
+@page mqttpropadd_pubcontenttype_function MQTTPropAdd_ContentType
+@snippet core_mqtt_serializer.h declare_mqttpropadd_contenttype
+@copydoc MQTTPropAdd_ContentType
+
+@page mqttpropadd_reasonstring_function MQTTPropAdd_ReasonString
+@snippet core_mqtt_serializer.h declare_mqttpropadd_reasonstring
+@copydoc MQTTPropAdd_ReasonString
+
+@page mqtt_validatesubscribeproperties_function MQTT_ValidateSubscribeProperties
+@snippet core_mqtt_serializer.h declare_mqtt_validatesubscribeproperties
+@copydoc MQTT_ValidateSubscribeProperties
+
+@page MQTTPropGet_payloadformat_function MQTTPropGet_PayloadFormatIndicator
+@snippet core_mqtt_serializer.h declare_mqttpropget_payloadformatindicator
+@copydoc MQTTPropGet_PayloadFormatIndicator
+
+@page MQTTPropGet_responsetopic_function MQTTPropGet_ResponseTopic
+@snippet core_mqtt_serializer.h declare_mqttpropget_responsetopic
+@copydoc MQTTPropGet_ResponseTopic
+
+@page MQTTPropGet_correlationdata_function MQTTPropGet_CorrelationData
+@snippet core_mqtt_serializer.h declare_mqttpropget_correlationdata
+@copydoc MQTTPropGet_CorrelationData
+
+@page MQTTPropGet_messageexpiryinterval_function MQTTPropGet_MessageExpiryInterval
+@snippet core_mqtt_serializer.h declare_mqttpropget_messageexpiryinterval
+@copydoc MQTTPropGet_MessageExpiryInterval
+
+@page MQTTPropGet_contenttype_function MQTTPropGet_ContentType
+@snippet core_mqtt_serializer.h declare_mqttpropget_contenttype
+@copydoc MQTTPropGet_ContentType
+
+@page MQTTPropGet_subscriptionid_function MQTTPropGet_SubscriptionId
+@snippet core_mqtt_serializer.h declare_mqttpropget_subscriptionid
+@copydoc MQTTPropGet_SubscriptionId
+
+@page mqttpropget_userprop_function MQTTPropGet_UserProp
+@snippet core_mqtt_serializer.h declare_mqttpropget_userprop
+@copydoc MQTTPropGet_UserProp
+
+@page mqttpropget_reasonstring_function MQTTPropGet_ReasonString
+@snippet core_mqtt_serializer.h declare_mqttpropget_reasonstring
+@copydoc MQTTPropGet_ReasonString
+
+@page mqttpropget_disconnectserverref_function MQTTPropGet_ServerRef
+@snippet core_mqtt_serializer.h declare_mqttpropget_serverref
+@copydoc MQTTPropGet_ServerRef
+
+@page mqttpropget_sessionexpiry_function MQTTPropGet_SessionExpiry
+@snippet core_mqtt_serializer.h declare_mqttpropget_sessionexpiry
+@copydoc MQTTPropGet_SessionExpiry
+
+@page MQTTPropGet_topicaliasmax_function MQTTPropGet_TopicAliasMax
+@snippet core_mqtt_serializer.h declare_mqttpropget_topicaliasmax
+@copydoc MQTTPropGet_TopicAliasMax
+
+@page MQTTPropGet_receivemax_function MQTTPropGet_ReceiveMax
+@snippet core_mqtt_serializer.h declare_mqttpropget_receivemax
+@copydoc MQTTPropGet_ReceiveMax
+
+@page MQTTPropGet_maxqos_function MQTTPropGet_MaxQos
+@snippet core_mqtt_serializer.h declare_mqttpropget_maxqos
+@copydoc MQTTPropGet_MaxQos
+
+@page MQTTPropGet_retainavailable_function MQTTPropGet_RetainAvailable
+@snippet core_mqtt_serializer.h declare_mqttpropget_retainavailable
+@copydoc MQTTPropGet_RetainAvailable
+
+@page MQTTPropGet_maxpacketsize_function MQTTPropGet_MaxPacketSize
+@snippet core_mqtt_serializer.h declare_mqttpropget_maxpacketsize
+@copydoc MQTTPropGet_MaxPacketSize
+
+@page mqtt_initconnect_function MQTT_InitConnect
+@snippet core_mqtt_serializer.h declare_mqtt_initconnect
+@copydoc MQTT_InitConnect
+
*/
/**
diff --git a/mqttFilePaths.cmake b/mqttFilePaths.cmake
index 90c942b7d..9bf5264dd 100644
--- a/mqttFilePaths.cmake
+++ b/mqttFilePaths.cmake
@@ -12,7 +12,10 @@ set( MQTT_SOURCES
# MQTT Serializer library source files.
set( MQTT_SERIALIZER_SOURCES
- "${CMAKE_CURRENT_LIST_DIR}/source/core_mqtt_serializer.c" )
+ "${CMAKE_CURRENT_LIST_DIR}/source/core_mqtt_serializer.c"
+ "${CMAKE_CURRENT_LIST_DIR}/source/core_mqtt_prop_serializer.c"
+ "${CMAKE_CURRENT_LIST_DIR}/source/core_mqtt_prop_deserializer.c"
+ "${CMAKE_CURRENT_LIST_DIR}/source/core_mqtt_serializer_private.c" )
# MQTT library Public Include directories.
set( MQTT_INCLUDE_PUBLIC_DIRS
diff --git a/source/core_mqtt.c b/source/core_mqtt.c
index c7460c26c..c02b157d7 100644
--- a/source/core_mqtt.c
+++ b/source/core_mqtt.c
@@ -28,29 +28,21 @@
*/
#include
#include
+#include
+#include
+#include
+#include
#include "core_mqtt.h"
+#include "core_mqtt_serializer.h"
+#include "transport_interface.h"
#include "core_mqtt_state.h"
+#include "private/core_mqtt_serializer_private.h"
+
/* Include config defaults header to get default values of configs. */
#include "core_mqtt_config_defaults.h"
-#ifndef MQTT_PRE_SEND_HOOK
-
-/**
- * @brief Hook called before a 'send' operation is executed.
- */
- #define MQTT_PRE_SEND_HOOK( pContext )
-#endif /* !MQTT_PRE_SEND_HOOK */
-
-#ifndef MQTT_POST_SEND_HOOK
-
-/**
- * @brief Hook called after the 'send' operation is complete.
- */
- #define MQTT_POST_SEND_HOOK( pContext )
-#endif /* !MQTT_POST_SEND_HOOK */
-
#ifndef MQTT_PRE_STATE_UPDATE_HOOK
/**
@@ -78,7 +70,7 @@
* @brief Number of vectors required to encode one topic filter in a subscribe
* request. Three vectors are required as there are three fields in the
* subscribe request namely:
- * 1. Topic filter length; 2. Topic filter; and 3. QoS in this order.
+ * 1. Topic filter length; 2. Topic filter; and 3. Subscription options in this order.
*/
#define CORE_MQTT_SUBSCRIBE_PER_TOPIC_VECTOR_LENGTH ( 3U )
@@ -123,12 +115,13 @@ static int32_t sendBuffer( MQTTContext_t * pContext,
/**
* @brief Sends MQTT connect without copying the users data into any buffer.
*
- * @brief param[in] pContext Initialized MQTT context.
- * @brief param[in] pConnectInfo MQTT CONNECT packet information.
- * @brief param[in] pWillInfo Last Will and Testament. Pass NULL if Last Will and
+ * @param[in] pContext Initialized MQTT context.
+ * @param[in] pConnectInfo MQTT CONNECT packet information.
+ * @param[in] pWillInfo Last Will and Testament. Pass NULL if Last Will and
* Testament is not used.
- * @brief param[in] remainingLength the length of the connect packet.
- *
+ * @param[in] remainingLength the length of the connect packet.
+ * @param[in] pPropertyBuilder Property builder containing CONNECT properties.
+ * @param[in] pWillPropertyBuilder Property builder containing Last Will And Testament properties.
* @note This operation may call the transport send function
* repeatedly to send bytes over the network until either:
* 1. The requested number of bytes @a remainingLength have been sent.
@@ -138,12 +131,14 @@ static int32_t sendBuffer( MQTTContext_t * pContext,
* OR
* 3. There is an error in sending data over the network.
*
- * @return #MQTTSendFailed or #MQTTSuccess.
+ * @return #MQTTSendFailed, #MQTTBadParameter, #MQTTBadResponse or #MQTTSuccess.
*/
static MQTTStatus_t sendConnectWithoutCopy( MQTTContext_t * pContext,
const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength );
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTPropBuilder_t * pWillPropertyBuilder );
/**
* @brief Sends the vector array passed through the parameters over the network.
@@ -191,43 +186,62 @@ static size_t addEncodedStringToVector( uint8_t serializedLength[ CORE_MQTT_SERI
const char * const string,
uint16_t length,
TransportOutVector_t * iterator,
- size_t * updatedLength );
+ uint32_t * updatedLength );
/**
- * @brief Send MQTT SUBSCRIBE message without copying the user data into a buffer and
- * directly sending it.
+ * @brief Send Subscribe without copying the users data into any buffer.
*
* @param[in] pContext Initialized MQTT context.
* @param[in] pSubscriptionList List of MQTT subscription info.
- * @param[in] subscriptionCount The count of elements in the list.
- * @param[in] packetId The packet ID of the subscribe packet
- * @param[in] remainingLength The remaining length of the subscribe packet.
+ * @param[in] subscriptionCount Number of elements in pSubscriptionList.
+ * @param[in] packetId Packet identifier.
+ * @param[in] remainingLength Remaining length of the packet.
+ * @param[in] pPropertyBuilder MQTT property builder.
+ * @note This operation may call the transport send function
+ * repeatedly to send bytes over the network until either:
+ * 1. The requested number of bytes @a remainingLength have been sent.
+ * OR
+ * 2. MQTT_SEND_TIMEOUT_MS milliseconds have gone by since entering this
+ * function.
+ * OR
+ * 3. There is an error in sending data over the network.
*
- * @return #MQTTSuccess or #MQTTSendFailed.
+ * @return #MQTTSendFailed or #MQTTSuccess.
*/
+
static MQTTStatus_t sendSubscribeWithoutCopy( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength );
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder );
/**
- * @brief Send MQTT UNSUBSCRIBE message without copying the user data into a buffer and
- * directly sending it.
+ * @brief Send Unsubscribe without copying the users data into any buffer.
*
* @param[in] pContext Initialized MQTT context.
- * @param[in] pSubscriptionList MQTT subscription info.
- * @param[in] subscriptionCount The count of elements in the list.
- * @param[in] packetId The packet ID of the unsubscribe packet.
- * @param[in] remainingLength The remaining length of the unsubscribe packet.
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] subscriptionCount Number of elements in pSubscriptionList.
+ * @param[in] packetId Packet identifier.
+ * @param[in] remainingLength Remaining length of the packet.
+ * @param[in] pPropertyBuilder MQTT property builder.
+ * @note This operation may call the transport send function
+ * repeatedly to send bytes over the network until either:
+ * 1. The requested number of bytes @a remainingLength have been sent.
+ * OR
+ * 2. MQTT_SEND_TIMEOUT_MS milliseconds have gone by since entering this
+ * function.
+ * OR
+ * 3. There is an error in sending data over the network.
*
- * @return #MQTTSuccess or #MQTTSendFailed.
+ * @return #MQTTSendFailed or #MQTTSuccess.
*/
static MQTTStatus_t sendUnsubscribeWithoutCopy( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength );
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder );
/**
* @brief Calculate the interval between two millisecond timestamps, including
@@ -276,41 +290,15 @@ static int32_t recvExact( MQTTContext_t * pContext,
size_t bytesToRecv );
/**
- * @brief Discard a packet from the transport interface.
- *
- * @param[in] pContext MQTT Connection context.
- * @param[in] remainingLength Remaining length of the packet to dump.
- * @param[in] timeoutMs Time remaining to discard the packet.
- *
- * @return #MQTTRecvFailed or #MQTTNoDataAvailable.
- */
-static MQTTStatus_t discardPacket( MQTTContext_t * pContext,
- size_t remainingLength,
- uint32_t timeoutMs );
-
-/**
- * @brief Discard a packet from the MQTT buffer and the transport interface.
- *
- * @param[in] pContext MQTT Connection context.
- * @param[in] pPacketInfo Information struct of the packet to be discarded.
- *
- * @return #MQTTRecvFailed or #MQTTNoDataAvailable.
- */
-static MQTTStatus_t discardStoredPacket( MQTTContext_t * pContext,
- const MQTTPacketInfo_t * pPacketInfo );
-
-/**
- * @brief Receive a packet from the transport interface.
+ * @brief Receive a CONNACK packet from the transport interface.
*
* @param[in] pContext MQTT Connection context.
* @param[in] incomingPacket packet struct with remaining length.
- * @param[in] remainingTimeMs Time remaining to receive the packet.
*
* @return #MQTTSuccess or #MQTTRecvFailed.
*/
-static MQTTStatus_t receivePacket( MQTTContext_t * pContext,
- MQTTPacketInfo_t incomingPacket,
- uint32_t remainingTimeMs );
+static MQTTStatus_t receiveConnackPacket( MQTTContext_t * pContext,
+ MQTTPacketInfo_t incomingPacket );
/**
* @brief Get the correct ack type to send.
@@ -406,6 +394,7 @@ static MQTTStatus_t receiveSingleIteration( MQTTContext_t * pContext,
* @param[in] pSubscriptionList List of MQTT subscription info.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
* @param[in] packetId Packet identifier.
+ * @param[in] subscriptionType Either #MQTT_TYPE_SUBSCRIBE or #MQTT_TYPE_UNSUBSCRIBE.
*
* @return #MQTTBadParameter if invalid parameters are passed;
* #MQTTSuccess otherwise.
@@ -413,7 +402,8 @@ static MQTTStatus_t receiveSingleIteration( MQTTContext_t * pContext,
static MQTTStatus_t validateSubscribeUnsubscribeParams( const MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId );
+ uint16_t packetId,
+ MQTTSubscriptionType_t subscriptionType );
/**
* @brief Receives a CONNACK MQTT packet.
@@ -459,28 +449,31 @@ static MQTTStatus_t handleCleanSession( MQTTContext_t * pContext );
* @brief Send the publish packet without copying the topic string and payload in
* the buffer.
*
- * @brief param[in] pContext Initialized MQTT context.
- * @brief param[in] pPublishInfo MQTT PUBLISH packet parameters.
- * @brief param[in] pMqttHeader the serialized MQTT header with the header byte;
+ * @param[in] pContext Initialized MQTT context.
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] pMqttHeader the serialized MQTT header with the header byte;
* the encoded length of the packet; and the encoded length of the topic string.
- * @brief param[in] headerSize Size of the serialized PUBLISH header.
- * @brief param[in] packetId Packet Id of the publish packet.
+ * @param[in] headerSize Size of the serialized PUBLISH header.
+ * @param[in] packetId Packet Id of the publish packet.
+ * @param[in] pPropertyBuilder MQTT Publish property builder.
*
* @return #MQTTSendFailed if transport send during resend failed;
+ * #MQTTPublishStoreFailed if storing the outgoing publish failed in the case of QoS 1/2
* #MQTTSuccess otherwise.
*/
static MQTTStatus_t sendPublishWithoutCopy( MQTTContext_t * pContext,
const MQTTPublishInfo_t * pPublishInfo,
uint8_t * pMqttHeader,
size_t headerSize,
- uint16_t packetId );
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder );
/**
* @brief Function to validate #MQTT_Publish parameters.
*
- * @brief param[in] pContext Initialized MQTT context.
- * @brief param[in] pPublishInfo MQTT PUBLISH packet parameters.
- * @brief param[in] packetId Packet Id for the MQTT PUBLISH packet.
+ * @param[in] pContext Initialized MQTT context.
+ * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] packetId Packet Id for the MQTT PUBLISH packet.
*
* @return #MQTTBadParameter if invalid parameters are passed;
* #MQTTSuccess otherwise.
@@ -558,6 +551,146 @@ static bool matchTopicFilter( const char * pTopicName,
const char * pTopicFilter,
uint16_t topicFilterLength );
+/**
+ * @brief Validate the topic filter in a subscription.
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] iterator The iterator pointing to a topic filter in pSubscriptionList.
+ * @param[in] subscriptionType The type of subscription, either #MQTT_TYPE_SUBSCRIBE or #MQTT_TYPE_UNSUBSCRIBE.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the topic filter is valid
+ * - #MQTTBadParameter if the topic filter is invalid or parameters are NULL
+ */
+static MQTTStatus_t validateTopicFilter( const MQTTContext_t * pContext,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ size_t iterator,
+ MQTTSubscriptionType_t subscriptionType );
+
+/**
+ * @brief Check if wildcard subscriptions are allowed and valid.
+ *
+ * @param[in] isWildcardAvailable Flag indicating if wildcard subscriptions are supported.
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] iterator The iterator pointing to a topic filter in pSubscriptionList.
+ *
+ * @return true if wildcard subscriptions are valid or not present;
+ * false if wildcards are used but not supported
+ */
+static bool checkWildcardSubscriptions( uint8_t isWildcardAvailable,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ size_t iterator );
+
+/**
+ * @brief Validate Shared Subscriptions
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] iterator The iterator pointing to a topic filter in pSubscriptionList.
+ *
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise
+ * */
+static MQTTStatus_t validateSharedSubscriptions( const MQTTContext_t * pContext,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ const size_t iterator );
+
+/**
+ * @brief Add subscription options to the options array.
+ *
+ * @param[in] subscriptionInfo MQTT subscription information.
+ * @param[out] pSubscriptionOptionsArray Array to store subscription options.
+ * @param[in] currentOptionIndex Current index in the options array.
+ *
+ * @note This function does not return a status as it performs a direct array update.
+ */
+static void addSubscriptionOptions( const MQTTSubscribeInfo_t subscriptionInfo,
+ uint8_t * pSubscriptionOptionsArray,
+ size_t currentOptionIndex );
+
+/**
+ * @brief Handle Incoming Subscribe ACK
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] pIncomingPacket Information of incoming packet
+ *
+ * @return #MQTTSuccess, #MQTTServerRefused, #MQTTBadResponse, #MQTTBadParameter, #MQTTEventCallbackFailed.
+ */
+static MQTTStatus_t handleSubUnsubAck( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pIncomingPacket );
+
+/**
+ * @brief Send acks for received QoS 1/2 publishes. This function is used to send
+ * Publish Acks without any properties or reason codes.
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] packetId packet ID of original PUBLISH.
+ * @param[in] publishState Current publish state in record.
+ *
+ * @return MQTTSuccess, MQTTBadParameter, MQTTBadResponse, MQTTIllegalState, MQTTSendFailed, MQTTStatusNotConnected, MQTTStatusDisconnectPending or MQTTNoMemory.
+ */
+static MQTTStatus_t sendPublishAcksWithoutProperty( MQTTContext_t * pContext,
+ uint16_t packetId,
+ MQTTPublishState_t publishState );
+
+/**
+ * @brief Send acks for received QoS 1/2 publishes with properties.
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] packetId packet ID of original PUBLISH.
+ * @param[in] publishState Current publish state in record.
+ * @param[in] reasonCode Reason code to be sent in the Publish Ack.
+ *
+ * @return #MQTTSuccess, #MQTTBadParameter, #MQTTIllegalState, #MQTTSendFailed, #MQTTStatusNotConnected, #MQTTStatusDisconnectPending or #MQTTBadResponse.
+ */
+static MQTTStatus_t sendPublishAcksWithProperty( MQTTContext_t * pContext,
+ uint16_t packetId,
+ MQTTPublishState_t publishState,
+ MQTTSuccessFailReasonCode_t reasonCode );
+
+/**
+ * @brief Validate Publish Ack Reason Code
+ *
+ * @param[in] reasonCode Reason Code to validate
+ * @param[in] packetType Packet Type byte of the publish ack packet. (PUBACK, PUBREC, PUBREL, PUBCOMP)
+ *
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise
+ */
+static MQTTStatus_t validatePublishAckReasonCode( MQTTSuccessFailReasonCode_t reasonCode,
+ uint8_t packetType );
+
+/**
+ * @brief Send the disconnect packet without copying the reason code and properties in
+ * the buffer.
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] pReasonCode Optional reason code to be sent in the Disconnect packet.
+ * @param[in] remainingLength Remaining length of the packet.
+ * @param[in] pPropertyBuilder MQTT Disconnect property builder.
+ *
+ *
+ * @return #MQTTSendFailed if transport send during resend failed;
+ * #MQTTSuccess otherwise.
+ */
+
+static MQTTStatus_t sendDisconnectWithoutCopy( MQTTContext_t * pContext,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder );
+
+/**
+ * @brief Handle Incoming Disconnect
+ *
+ * @param[in] pContext MQTT Connection context.
+ * @param[in] pIncomingPacket Information of incoming packet
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse, #MQTTBadParameter, #MQTTEventCallbackFailed,
+ */
+static MQTTStatus_t handleIncomingDisconnect( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pIncomingPacket );
+
/*-----------------------------------------------------------*/
static bool matchEndWildcardsSpecialCases( const char * pTopicFilter,
@@ -572,7 +705,7 @@ static bool matchEndWildcardsSpecialCases( const char * pTopicFilter,
/* Check if the topic filter has 2 remaining characters and it ends in
* "/#". This check handles the case to match filter "sport/#" with topic
* "sport". The reason is that the '#' wildcard represents the parent and
- * any number of child levels in the topic name.*/
+ * any number of child levels in the topic name. */
if( ( topicFilterLength >= 3U ) &&
( filterIndex == ( topicFilterLength - 3U ) ) &&
( pTopicFilter[ filterIndex + 1U ] == '/' ) &&
@@ -624,7 +757,7 @@ static bool matchWildcards( const char * pTopicName,
nameIndex = *pNameIndex;
/* Wild card in a topic filter is only valid either at the starting position
- * or when it is preceded by a '/'.*/
+ * or when it is preceded by a '/'. */
locationIsValidForWildcard = ( *pFilterIndex == 0u ) ||
( pTopicFilter[ *pFilterIndex - 1U ] == '/' );
@@ -679,7 +812,7 @@ static bool matchWildcards( const char * pTopicName,
/* If we have reached here, the the loop terminated on the
* ( nameIndex < topicNameLength) condition, which means that have
* reached past the end of the topic name, and thus, we decrement the
- * index to the last character in the topic name.*/
+ * index to the last character in the topic name. */
/* coverity[integer_overflow] */
nameIndex -= 1;
}
@@ -785,7 +918,7 @@ static int32_t sendMessageVector( MQTTContext_t * pContext,
uint32_t startTime;
TransportOutVector_t * pIoVectIterator;
size_t vectorsToBeSent = ioVecCount;
- size_t bytesToSend = 0U;
+ uint32_t bytesToSend = 0U;
int32_t bytesSentOrError = 0;
assert( pContext != NULL );
@@ -797,6 +930,12 @@ static int32_t sendMessageVector( MQTTContext_t * pContext,
/* Count the total number of bytes to be sent as outlined in the vector. */
for( pIoVectIterator = pIoVec; pIoVectIterator <= &( pIoVec[ ioVecCount - 1U ] ); pIoVectIterator++ )
{
+ /* Before calling this function, the caller has checked that these below conditions
+ * are true. */
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pIoVectIterator->iov_len ) );
+ assert( !ADDITION_WILL_OVERFLOW_U32( bytesToSend, pIoVectIterator->iov_len ) );
+ assert( pIoVectIterator->iov_len <= ( MQTT_MAX_PACKET_SIZE - bytesToSend ) );
+
bytesToSend += pIoVectIterator->iov_len;
}
@@ -858,7 +997,9 @@ static int32_t sendMessageVector( MQTTContext_t * pContext,
break;
}
- /* Update the send pointer to the correct vector and offset. */
+ /* Update the send pointer to the correct vector and offset. Here, it is fine
+ * to cast iov_len (size_t) to int32_t since we have verified that, individually,
+ * they all must be smaller than MQTT_MAX_PACKET_SIZE. */
while( ( pIoVectIterator <= &( pIoVec[ ioVecCount - 1U ] ) ) &&
( sendResult >= ( int32_t ) pIoVectIterator->iov_len ) )
{
@@ -894,26 +1035,36 @@ static int32_t sendBuffer( MQTTContext_t * pContext,
uint32_t startTime;
int32_t bytesSentOrError = 0;
const uint8_t * pIndex = pBufferToSend;
+ int32_t localCopyBytesToSend;
assert( pContext != NULL );
assert( pContext->getTime != NULL );
assert( pContext->transportInterface.send != NULL );
assert( pIndex != NULL );
+ assert( CHECK_SIZE_T_OVERFLOWS_32BIT( bytesToSend ) != true );
+
+ /* Since this function is always called to send one MQTT packet at
+ * a time, we can assert on the following. */
+ assert( bytesToSend <= MQTT_MAX_PACKET_SIZE );
+
+ /* As we asserted that bytes to send variable must be smaller than
+ * MQTT max packet length, it can comfortably fit in an int32_t. */
+ localCopyBytesToSend = ( int32_t ) bytesToSend;
/* Set the timeout. */
startTime = pContext->getTime();
- while( ( bytesSentOrError < ( int32_t ) bytesToSend ) && ( bytesSentOrError >= 0 ) )
+ while( ( bytesSentOrError < localCopyBytesToSend ) && ( bytesSentOrError >= 0 ) )
{
sendResult = pContext->transportInterface.send( pContext->transportInterface.pNetworkContext,
pIndex,
- bytesToSend - ( size_t ) bytesSentOrError );
+ localCopyBytesToSend - bytesSentOrError );
if( sendResult > 0 )
{
/* It is a bug in the application's transport send implementation if
* more bytes than expected are sent. */
- assert( sendResult <= ( ( int32_t ) bytesToSend - bytesSentOrError ) );
+ assert( sendResult <= ( localCopyBytesToSend - bytesSentOrError ) );
bytesSentOrError += sendResult;
pIndex = &pIndex[ sendResult ];
@@ -923,7 +1074,7 @@ static int32_t sendBuffer( MQTTContext_t * pContext,
LogDebug( ( "sendBuffer: Bytes Sent=%ld, Bytes Remaining=%lu",
( long int ) sendResult,
- ( unsigned long ) ( bytesToSend - ( size_t ) bytesSentOrError ) ) );
+ ( unsigned long ) ( localCopyBytesToSend - bytesSentOrError ) ) );
}
else if( sendResult < 0 )
{
@@ -1079,145 +1230,8 @@ static int32_t recvExact( MQTTContext_t * pContext,
/*-----------------------------------------------------------*/
-static MQTTStatus_t discardPacket( MQTTContext_t * pContext,
- size_t remainingLength,
- uint32_t timeoutMs )
-{
- MQTTStatus_t status = MQTTRecvFailed;
- int32_t bytesReceived = 0;
- size_t bytesToReceive = 0U;
- uint32_t totalBytesReceived = 0U;
- uint32_t entryTimeMs = 0U;
- uint32_t elapsedTimeMs = 0U;
- MQTTGetCurrentTimeFunc_t getTimeStampMs = NULL;
- bool receiveError = false;
-
- assert( pContext != NULL );
- assert( pContext->getTime != NULL );
-
- bytesToReceive = pContext->networkBuffer.size;
- getTimeStampMs = pContext->getTime;
-
- entryTimeMs = getTimeStampMs();
-
- while( ( totalBytesReceived < remainingLength ) && ( receiveError == false ) )
- {
- if( ( remainingLength - totalBytesReceived ) < bytesToReceive )
- {
- bytesToReceive = remainingLength - totalBytesReceived;
- }
-
- bytesReceived = recvExact( pContext, bytesToReceive );
-
- if( bytesReceived != ( int32_t ) bytesToReceive )
- {
- LogError( ( "Receive error while discarding packet."
- "ReceivedBytes=%ld, ExpectedBytes=%lu.",
- ( long int ) bytesReceived,
- ( unsigned long ) bytesToReceive ) );
- receiveError = true;
- }
- else
- {
- totalBytesReceived += ( uint32_t ) bytesReceived;
-
- elapsedTimeMs = calculateElapsedTime( getTimeStampMs(), entryTimeMs );
-
- /* Check for timeout. */
- if( elapsedTimeMs >= timeoutMs )
- {
- LogError( ( "Time expired while discarding packet." ) );
- receiveError = true;
- }
- }
- }
-
- if( totalBytesReceived == remainingLength )
- {
- LogError( ( "Dumped packet. DumpedBytes=%lu.",
- ( unsigned long ) totalBytesReceived ) );
- /* Packet dumped, so no data is available. */
- status = MQTTNoDataAvailable;
- }
-
- return status;
-}
-
-/*-----------------------------------------------------------*/
-
-static MQTTStatus_t discardStoredPacket( MQTTContext_t * pContext,
- const MQTTPacketInfo_t * pPacketInfo )
-{
- MQTTStatus_t status = MQTTRecvFailed;
- int32_t bytesReceived = 0;
- size_t bytesToReceive = 0U;
- uint32_t totalBytesReceived = 0U;
- bool receiveError = false;
- size_t mqttPacketSize = 0;
- size_t remainingLength;
-
- assert( pContext != NULL );
- assert( pPacketInfo != NULL );
-
- mqttPacketSize = pPacketInfo->remainingLength + pPacketInfo->headerLength;
-
- /* Assert that the packet being discarded is bigger than the
- * receive buffer. */
- assert( mqttPacketSize > pContext->networkBuffer.size );
-
- /* Discard these many bytes at a time. */
- bytesToReceive = pContext->networkBuffer.size;
-
- /* Number of bytes depicted by 'index' have already been received. */
- remainingLength = mqttPacketSize - pContext->index;
-
- while( ( totalBytesReceived < remainingLength ) && ( receiveError == false ) )
- {
- if( ( remainingLength - totalBytesReceived ) < bytesToReceive )
- {
- bytesToReceive = remainingLength - totalBytesReceived;
- }
-
- bytesReceived = recvExact( pContext, bytesToReceive );
-
- if( bytesReceived != ( int32_t ) bytesToReceive )
- {
- LogError( ( "Receive error while discarding packet."
- "ReceivedBytes=%ld, ExpectedBytes=%lu.",
- ( long int ) bytesReceived,
- ( unsigned long ) bytesToReceive ) );
- receiveError = true;
- }
- else
- {
- totalBytesReceived += ( uint32_t ) bytesReceived;
- }
- }
-
- if( totalBytesReceived == remainingLength )
- {
- LogError( ( "Dumped packet. DumpedBytes=%lu.",
- ( unsigned long ) totalBytesReceived ) );
- /* Packet dumped, so no data is available. */
- status = MQTTNoDataAvailable;
- }
-
- /* Clear the buffer */
- ( void ) memset( pContext->networkBuffer.pBuffer,
- 0,
- pContext->networkBuffer.size );
-
- /* Reset the index. */
- pContext->index = 0;
-
- return status;
-}
-
-/*-----------------------------------------------------------*/
-
-static MQTTStatus_t receivePacket( MQTTContext_t * pContext,
- MQTTPacketInfo_t incomingPacket,
- uint32_t remainingTimeMs )
+static MQTTStatus_t receiveConnackPacket( MQTTContext_t * pContext,
+ MQTTPacketInfo_t incomingPacket )
{
MQTTStatus_t status = MQTTSuccess;
int32_t bytesReceived = 0;
@@ -1225,17 +1239,16 @@ static MQTTStatus_t receivePacket( MQTTContext_t * pContext,
assert( pContext != NULL );
assert( pContext->networkBuffer.pBuffer != NULL );
+ assert( incomingPacket.type == MQTT_PACKET_TYPE_CONNACK );
+ assert( incomingPacket.remainingLength < MQTT_REMAINING_LENGTH_INVALID );
+ assert( !CHECK_U32T_OVERFLOWS_SIZE_T( incomingPacket.remainingLength ) );
if( incomingPacket.remainingLength > pContext->networkBuffer.size )
{
- LogError( ( "Incoming packet will be dumped: "
- "Packet length exceeds network buffer size."
- "PacketSize=%lu, NetworkBufferSize=%lu.",
- ( unsigned long ) incomingPacket.remainingLength,
- ( unsigned long ) pContext->networkBuffer.size ) );
- status = discardPacket( pContext,
- incomingPacket.remainingLength,
- remainingTimeMs );
+ LogError( ( "Incoming packet bigger than the application provided network buffer. Cannot "
+ "handle this packet as MQTT spec doesn't allow 'dropping' packets. Application "
+ "must provide a bigger buffer to handle such packets." ) );
+ status = MQTTRecvFailed;
}
else
{
@@ -1319,9 +1332,12 @@ static MQTTStatus_t sendPublishAcks( MQTTContext_t * pContext,
{
packetType = getAckFromPacketType( packetTypeByte );
+ /* TODO: check whether this should be sent with user properties and/or reason code. */
status = MQTT_SerializeAck( &localBuffer,
packetTypeByte,
- packetId );
+ packetId,
+ NULL,
+ NULL );
if( status == MQTTSuccess )
{
@@ -1440,46 +1456,408 @@ static MQTTStatus_t handleKeepAlive( MQTTContext_t * pContext )
/*-----------------------------------------------------------*/
-static MQTTStatus_t handleIncomingPublish( MQTTContext_t * pContext,
- MQTTPacketInfo_t * pIncomingPacket )
+static MQTTStatus_t sendPublishAcksWithoutProperty( MQTTContext_t * pContext,
+ uint16_t packetId,
+ MQTTPublishState_t publishState )
{
- MQTTStatus_t status;
- MQTTPublishState_t publishRecordState = MQTTStateNull;
- uint16_t packetIdentifier = 0U;
- MQTTPublishInfo_t publishInfo;
- MQTTDeserializedInfo_t deserializedInfo;
- bool duplicatePublish = false;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPublishState_t newState = MQTTStateNull;
+ int32_t sendResult = 0;
+ uint8_t packetTypeByte = 0U;
+ MQTTPubAckType_t packetType;
+ MQTTFixedBuffer_t localBuffer;
+ MQTTConnectionStatus_t connectStatus;
+ uint8_t pubAckPacket[ MQTT_PUBLISH_ACK_PACKET_SIZE ];
+
+ localBuffer.pBuffer = pubAckPacket;
+ localBuffer.size = MQTT_PUBLISH_ACK_PACKET_SIZE;
assert( pContext != NULL );
- assert( pIncomingPacket != NULL );
- assert( pContext->appCallback != NULL );
- status = MQTT_DeserializePublish( pIncomingPacket, &packetIdentifier, &publishInfo );
- LogInfo( ( "De-serialized incoming PUBLISH packet: DeserializerResult=%s.",
- MQTT_Status_strerror( status ) ) );
+ packetTypeByte = getAckTypeToSend( publishState );
- if( ( status == MQTTSuccess ) &&
- ( pContext->incomingPublishRecords == NULL ) &&
- ( publishInfo.qos > MQTTQoS0 ) )
- {
- LogError( ( "Incoming publish has QoS > MQTTQoS0 but incoming "
- "publish records have not been initialized. Dropping the "
- "incoming publish. Please call MQTT_InitStatefulQoS to enable "
- "use of QoS1 and QoS2 publishes." ) );
- status = MQTTRecvFailed;
- }
+ LogDebug( ( "Got ACK packet type 0x%02x [pkt ID: %hu] for the publish state 0x%02x",
+ packetTypeByte,
+ packetId,
+ publishState ) );
- if( status == MQTTSuccess )
+ if( packetTypeByte != 0U )
{
- MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ packetType = getAckFromPacketType( packetTypeByte );
- status = MQTT_UpdateStatePublish( pContext,
- packetIdentifier,
- MQTT_RECEIVE,
- publishInfo.qos,
- &publishRecordState );
+ status = MQTT_SerializeAck( &localBuffer,
+ packetTypeByte,
+ packetId,
+ NULL,
+ NULL );
- MQTT_POST_STATE_UPDATE_HOOK( pContext );
+ if( MQTT_PUBLISH_ACK_PACKET_SIZE > pContext->connectionProperties.serverMaxPacketSize )
+ {
+ LogError( ( "Packet size is greater than the allowed maximum packet size." ) );
+ status = MQTTBadParameter;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ {
+ connectStatus = pContext->connectStatus;
+
+ if( connectStatus != MQTTConnected )
+ {
+ status = ( connectStatus == MQTTNotConnected ) ? MQTTStatusNotConnected : MQTTStatusDisconnectPending;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Sending ACK packet: PacketType=%02x, PacketID=%hu.",
+ ( unsigned int ) packetTypeByte, ( unsigned short ) packetId ) );
+
+ /* Here, we are not using the vector approach for efficiency. There is just one buffer
+ * to be sent which can be achieved with a normal send call. */
+ sendResult = sendBuffer( pContext,
+ localBuffer.pBuffer,
+ MQTT_PUBLISH_ACK_PACKET_SIZE );
+
+ if( sendResult < ( int32_t ) MQTT_PUBLISH_ACK_PACKET_SIZE )
+ {
+ status = MQTTSendFailed;
+ }
+ }
+ }
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ pContext->controlPacketSent = true;
+
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ {
+ status = MQTT_UpdateStateAck( pContext,
+ packetId,
+ packetType,
+ MQTT_SEND,
+ &newState );
+ }
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Failed to update state of publish %hu.",
+ ( unsigned short ) packetId ) );
+ }
+ }
+ else
+ {
+ LogError( ( "Failed to send ACK packet: PacketType=%02x, SentBytes=%ld, "
+ "PacketSize=%lu.",
+ ( unsigned int ) packetTypeByte, ( long int ) sendResult,
+ MQTT_PUBLISH_ACK_PACKET_SIZE ) );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t sendPublishAcksWithProperty( MQTTContext_t * pContext,
+ uint16_t packetId,
+ MQTTPublishState_t publishState,
+ MQTTSuccessFailReasonCode_t reasonCode )
+{
+ int32_t bytesSentOrError;
+ size_t ioVectorLength = 0U;
+ uint32_t totalMessageLength = 0U;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPublishState_t newState = MQTTStateNull;
+ uint8_t packetTypeByte = 0U;
+ MQTTPubAckType_t packetType;
+ size_t ackPropertyLength = 0U;
+
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
+
+ /* Maximum number of bytes required by the fixed size properties and header.
+ * MQTT Control Byte 0 + 1 = 1
+ * Remaining length (max) + 4 = 5
+ * Packet Identifier + 2 = 7
+ * Reason Code + 1 = 8
+ */
+ uint8_t pubAckHeader[ 8U ];
+ uint32_t remainingLength = 0U;
+ uint32_t packetSize = 0U;
+
+ /* The maximum vectors required to encode and send a publish ack.
+ * Ack Header 0 + 1 = 1
+ * Property Length + 1 = 2
+ * Properties + 1 = 3
+ */
+
+ TransportOutVector_t pIoVector[ 3U ];
+
+ uint8_t * pIndex = pubAckHeader;
+ TransportOutVector_t * iterator = pIoVector;
+
+ assert( pContext != NULL );
+
+ if( pContext->ackPropsBuffer.pBuffer != NULL )
+ {
+ ackPropertyLength = pContext->ackPropsBuffer.currentIndex;
+ }
+
+ packetTypeByte = getAckTypeToSend( publishState );
+
+ LogDebug( ( "Got ACK packet type 0x%02x [pkt ID: %hu] for the publish state 0x%02x",
+ packetTypeByte,
+ packetId,
+ publishState ) );
+
+ if( packetTypeByte != 0U )
+ {
+ status = MQTT_ValidatePublishAckProperties( &pContext->ackPropsBuffer );
+
+ if( status == MQTTSuccess )
+ {
+ status = validatePublishAckReasonCode( reasonCode, packetTypeByte );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ status = MQTT_GetAckPacketSize( &remainingLength,
+ &packetSize,
+ pContext->connectionProperties.serverMaxPacketSize,
+ ackPropertyLength );
+ }
+ }
+
+ if( pContext->connectStatus != MQTTConnected )
+ {
+ status = ( pContext->connectStatus == MQTTNotConnected ) ? MQTTStatusNotConnected : MQTTStatusDisconnectPending;
+ }
+
+ if( ( packetTypeByte != 0U ) && ( status == MQTTSuccess ) )
+ {
+ packetType = getAckFromPacketType( packetTypeByte );
+
+ /* Only for fixed size fields. */
+ pIndex = serializeAckFixed( pIndex,
+ packetTypeByte,
+ packetId,
+ remainingLength,
+ reasonCode );
+ iterator->iov_base = pubAckHeader;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - pubAckHeader );
+
+ /* We can get away with asserts as the internal function serializeAckFixed is
+ * only serializing the 'header' fields. */
+ assert( iterator->iov_len < MQTT_MAX_PACKET_SIZE );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ if( ( pContext->ackPropsBuffer.pBuffer != NULL ) && ( ackPropertyLength != 0U ) )
+ {
+ /* Encode the property length. */
+ pIndex = encodeVariableLength( propertyLength, ackPropertyLength );
+ iterator->iov_base = propertyLength;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - propertyLength );
+
+ assert( iterator->iov_len < MQTT_MAX_PACKET_SIZE );
+ assert( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, iterator->iov_len ) == false );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ /* Encode the properties. */
+ iterator->iov_base = pContext->ackPropsBuffer.pBuffer;
+ iterator->iov_len = pContext->ackPropsBuffer.currentIndex;
+
+ assert( iterator->iov_len < MQTT_MAX_PACKET_SIZE );
+ assert( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, iterator->iov_len ) == false );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ /*
+ * Resetting buffer after sending the message.
+ */
+
+ pContext->ackPropsBuffer.currentIndex = 0;
+ pContext->ackPropsBuffer.fieldSet = 0;
+ }
+
+ if( totalMessageLength <= MQTT_MAX_PACKET_SIZE )
+ {
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ {
+ LogDebug( ( "Sending ACK packet: PacketType=%02x, PacketID=%hu.",
+ ( unsigned int ) packetTypeByte, ( unsigned short ) packetId ) );
+
+ bytesSentOrError = sendMessageVector( pContext, pIoVector, ioVectorLength );
+ }
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+
+ if( bytesSentOrError != ( int32_t ) totalMessageLength )
+ {
+ LogError( ( "Failed to send ACK packet: PacketType=%02x, "
+ "PacketSize=%" PRIu32,
+ ( unsigned int ) packetTypeByte,
+ packetSize ) );
+ status = MQTTSendFailed;
+ }
+ }
+ else
+ {
+ LogError( ( "Total message length cannot be larger than 268435460." ) );
+ status = MQTTBadParameter;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ pContext->controlPacketSent = true;
+
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ {
+ status = MQTT_UpdateStateAck( pContext,
+ packetId,
+ packetType,
+ MQTT_SEND,
+ &newState );
+ }
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Failed to update state of publish %hu.",
+ ( unsigned short ) packetId ) );
+ }
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validatePublishAckReasonCode( MQTTSuccessFailReasonCode_t reasonCode,
+ uint8_t packetType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ switch( reasonCode )
+ {
+ case MQTT_REASON_PUBACK_SUCCESS:
+ status = MQTTSuccess;
+ break;
+
+ case MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS:
+ case MQTT_REASON_PUBACK_UNSPECIFIED_ERROR:
+ case MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR:
+ case MQTT_REASON_PUBACK_NOT_AUTHORIZED:
+ case MQTT_REASON_PUBACK_TOPIC_NAME_INVALID:
+ case MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE:
+ case MQTT_REASON_PUBACK_QUOTA_EXCEEDED:
+ case MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID:
+
+ if( ( packetType == MQTT_PACKET_TYPE_PUBACK ) || ( packetType == MQTT_PACKET_TYPE_PUBREC ) )
+ {
+ status = MQTTSuccess;
+ }
+ else
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Invalid Reason Code for PUBREL or PUBCOMP packet." ) );
+ }
+
+ break;
+
+ case MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND:
+
+ if( ( packetType == MQTT_PACKET_TYPE_PUBREL ) || ( packetType == MQTT_PACKET_TYPE_PUBCOMP ) )
+ {
+ status = MQTTSuccess;
+ }
+ else
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Invalid Reason Code for PUBREC or PUBACK packet." ) );
+ }
+
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ LogError( ( "Invalid Reason Code." ) );
+ break;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t handleIncomingPublish( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ MQTTStatus_t status;
+ MQTTPublishState_t publishRecordState = MQTTStateNull;
+ uint16_t packetIdentifier = 0U;
+ MQTTPublishInfo_t publishInfo = { 0 };
+ MQTTDeserializedInfo_t deserializedInfo;
+ bool duplicatePublish = false;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ MQTTSuccessFailReasonCode_t reasonCode;
+ bool ackPropsAdded = false;
+
+ assert( pContext != NULL );
+ assert( pIncomingPacket != NULL );
+ assert( pContext->appCallback != NULL );
+
+ status = MQTT_DeserializePublish( pIncomingPacket,
+ &packetIdentifier,
+ &publishInfo,
+ &propBuffer,
+ pContext->connectionProperties.maxPacketSize,
+ pContext->connectionProperties.topicAliasMax );
+
+ LogInfo( ( "De-serialized incoming PUBLISH packet: DeserializerResult=%s.",
+ MQTT_Status_strerror( status ) ) );
+
+ if( ( status == MQTTSuccess ) &&
+ ( pContext->incomingPublishRecords == NULL ) &&
+ ( publishInfo.qos > MQTTQoS0 ) )
+ {
+ LogError( ( "Incoming publish has QoS > MQTTQoS0 but incoming "
+ "publish records have not been initialized. Dropping the "
+ "incoming publish. Please call MQTT_InitStatefulQoS to enable "
+ "use of QoS1 and QoS2 publishes." ) );
+ status = MQTTRecvFailed;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+
+ status = MQTT_UpdateStatePublish( pContext,
+ packetIdentifier,
+ MQTT_RECEIVE,
+ publishInfo.qos,
+ &publishRecordState );
+
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
if( status == MQTTSuccess )
{
@@ -1542,26 +1920,70 @@ static MQTTStatus_t handleIncomingPublish( MQTTContext_t * pContext,
if( status == MQTTSuccess )
{
- /* Set fields of deserialized struct. */
deserializedInfo.packetIdentifier = packetIdentifier;
deserializedInfo.pPublishInfo = &publishInfo;
deserializedInfo.deserializationResult = status;
/* Invoke application callback to hand the buffer over to application
- * before sending acks.
- * Application callback will be invoked for all publishes, except for
- * duplicate incoming publishes. */
+ * before sending acks. */
+ reasonCode = MQTT_INVALID_REASON_CODE;
+
if( duplicatePublish == false )
{
- pContext->appCallback( pContext,
- pIncomingPacket,
- &deserializedInfo );
+ MQTTPropBuilder_t * pTempPropBuffer = NULL;
+
+ if( publishInfo.qos > MQTTQoS0 )
+ {
+ pTempPropBuffer = &pContext->ackPropsBuffer;
+ }
+
+ if( pContext->appCallback( pContext, pIncomingPacket, &deserializedInfo,
+ &reasonCode, pTempPropBuffer, &propBuffer ) == false )
+ {
+ /* TODO: Figure out whether this should block the library
+ * from processing any more packets. */
+ status = MQTTEventCallbackFailed;
+ }
+ else if( publishInfo.qos > MQTTQoS0 )
+ {
+ if( ( pTempPropBuffer->pBuffer != NULL ) &&
+ ( CHECK_SIZE_T_OVERFLOWS_32BIT( pTempPropBuffer->currentIndex ) ||
+ ( pTempPropBuffer->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) ) )
+ {
+ status = MQTTSendFailed;
+ LogError( ( "Length of properties to be sent must be less than 268435456." ) );
+ }
+ else
+ {
+ /* Send PUBREC or PUBCOMP if necessary. */
+ ackPropsAdded = ( pContext->ackPropsBuffer.pBuffer != NULL ) &&
+ ( pContext->ackPropsBuffer.currentIndex > 0U );
+ }
+ }
+ else
+ {
+ /* Nothing to be done. QoS0 incoming publish handled successfully. */
+ }
}
- /* Send PUBACK or PUBREC if necessary. */
- status = sendPublishAcks( pContext,
- packetIdentifier,
- publishRecordState );
+ if( ( status == MQTTSuccess ) && ( publishInfo.qos > MQTTQoS0 ) )
+ {
+ if( ( ackPropsAdded == false ) && ( reasonCode == MQTT_INVALID_REASON_CODE ) )
+ {
+ LogTrace( ( "No reason code provided by application. Sending default reason code." ) );
+ status = sendPublishAcksWithoutProperty( pContext,
+ packetIdentifier,
+ publishRecordState );
+ }
+ else
+ {
+ LogTrace( ( "Reason code provided by application. Sending reason code." ) );
+ status = sendPublishAcksWithProperty( pContext,
+ packetIdentifier,
+ publishRecordState,
+ reasonCode );
+ }
+ }
}
return status;
@@ -1578,6 +2000,11 @@ static MQTTStatus_t handlePublishAcks( MQTTContext_t * pContext,
MQTTPubAckType_t ackType;
MQTTEventCallback_t appCallback;
MQTTDeserializedInfo_t deserializedInfo;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ MQTTSuccessFailReasonCode_t reasonCode;
+ bool ackPropsAdded;
+
+ MQTTReasonCodeInfo_t incomingReasonCode = { 0 };
assert( pContext != NULL );
assert( pIncomingPacket != NULL );
@@ -1586,20 +2013,28 @@ static MQTTStatus_t handlePublishAcks( MQTTContext_t * pContext,
appCallback = pContext->appCallback;
ackType = getAckFromPacketType( pIncomingPacket->type );
- status = MQTT_DeserializeAck( pIncomingPacket, &packetIdentifier, NULL );
- LogInfo( ( "Ack packet deserialized with result: %s.",
- MQTT_Status_strerror( status ) ) );
+
+ status = MQTT_DeserializeAck( pIncomingPacket,
+ &packetIdentifier,
+ &incomingReasonCode,
+ &propBuffer,
+ &pContext->connectionProperties );
+
+ LogDebug( ( "Ack packet of type %s (packet ID: %" PRIu16 ") deserialized with result: %s.",
+ MQTT_GetPacketTypeString( pIncomingPacket->type ),
+ packetIdentifier,
+ MQTT_Status_strerror( status ) ) );
if( status == MQTTSuccess )
{
MQTT_PRE_STATE_UPDATE_HOOK( pContext );
-
- status = MQTT_UpdateStateAck( pContext,
- packetIdentifier,
- ackType,
- MQTT_RECEIVE,
- &publishRecordState );
-
+ {
+ status = MQTT_UpdateStateAck( pContext,
+ packetIdentifier,
+ ackType,
+ MQTT_RECEIVE,
+ &publishRecordState );
+ }
MQTT_POST_STATE_UPDATE_HOOK( pContext );
if( status == MQTTSuccess )
@@ -1627,19 +2062,55 @@ static MQTTStatus_t handlePublishAcks( MQTTContext_t * pContext,
if( status == MQTTSuccess )
{
- /* Set fields of deserialized struct. */
deserializedInfo.packetIdentifier = packetIdentifier;
deserializedInfo.deserializationResult = status;
deserializedInfo.pPublishInfo = NULL;
+ deserializedInfo.pReasonCode = &incomingReasonCode;
+
/* Invoke application callback to hand the buffer over to application
* before sending acks. */
- appCallback( pContext, pIncomingPacket, &deserializedInfo );
- /* Send PUBREL or PUBCOMP if necessary. */
- status = sendPublishAcks( pContext,
- packetIdentifier,
- publishRecordState );
+ reasonCode = MQTT_INVALID_REASON_CODE;
+
+ if( appCallback( pContext, pIncomingPacket, &deserializedInfo, &reasonCode,
+ &pContext->ackPropsBuffer, &propBuffer ) == false )
+ {
+ /* TODO: verify whether this should block the recv thread? */
+ status = MQTTEventCallbackFailed;
+ }
+ else if( ( pContext->ackPropsBuffer.pBuffer != NULL ) &&
+ ( CHECK_SIZE_T_OVERFLOWS_32BIT( pContext->ackPropsBuffer.currentIndex ) ||
+ ( pContext->ackPropsBuffer.currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) ) )
+ {
+ status = MQTTSendFailed;
+ LogError( ( "Length of properties to be sent must be less than 268435456." ) );
+ }
+ else
+ {
+ /* Send PUBREC or PUBCOMP if necessary. */
+ ackPropsAdded = ( pContext->ackPropsBuffer.pBuffer != NULL ) &&
+ ( pContext->ackPropsBuffer.currentIndex > 0U );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( ( ackPropsAdded == false ) && ( reasonCode == MQTT_INVALID_REASON_CODE ) )
+ {
+ LogTrace( ( "No reason code provided by application. Sending default reason code." ) );
+ status = sendPublishAcksWithoutProperty( pContext,
+ packetIdentifier,
+ publishRecordState );
+ }
+ else
+ {
+ LogTrace( ( "Reason code provided by application. Sending reason code." ) );
+ status = sendPublishAcksWithProperty( pContext,
+ packetIdentifier,
+ publishRecordState,
+ reasonCode );
+ }
+ }
}
return status;
@@ -1669,8 +2140,8 @@ static MQTTStatus_t handleIncomingAck( MQTTContext_t * pContext,
appCallback = pContext->appCallback;
- LogDebug( ( "Received packet of type %02x.",
- ( unsigned int ) pIncomingPacket->type ) );
+ LogTrace( ( "Received packet of type %s.",
+ MQTT_GetPacketTypeString( pIncomingPacket->type ) ) );
switch( pIncomingPacket->type )
{
@@ -1685,7 +2156,12 @@ static MQTTStatus_t handleIncomingAck( MQTTContext_t * pContext,
break;
case MQTT_PACKET_TYPE_PINGRESP:
- status = MQTT_DeserializeAck( pIncomingPacket, &packetIdentifier, NULL );
+ /* PINGRESP has no payload. Thus reason code and properties are NULL. */
+ status = MQTT_DeserializeAck( pIncomingPacket,
+ &packetIdentifier,
+ NULL,
+ NULL,
+ &pContext->connectionProperties );
invokeAppCallback = ( status == MQTTSuccess ) && !manageKeepAlive;
if( ( status == MQTTSuccess ) && ( manageKeepAlive == true ) )
@@ -1698,8 +2174,7 @@ static MQTTStatus_t handleIncomingAck( MQTTContext_t * pContext,
case MQTT_PACKET_TYPE_SUBACK:
case MQTT_PACKET_TYPE_UNSUBACK:
/* Deserialize and give these to the app provided callback. */
- status = MQTT_DeserializeAck( pIncomingPacket, &packetIdentifier, NULL );
- invokeAppCallback = ( status == MQTTSuccess ) || ( status == MQTTServerRefused );
+ status = handleSubUnsubAck( pContext, pIncomingPacket );
break;
default:
@@ -1716,13 +2191,50 @@ static MQTTStatus_t handleIncomingAck( MQTTContext_t * pContext,
deserializedInfo.packetIdentifier = packetIdentifier;
deserializedInfo.deserializationResult = status;
deserializedInfo.pPublishInfo = NULL;
- appCallback( pContext, pIncomingPacket, &deserializedInfo );
- /* In case a SUBACK indicated refusal, reset the status to continue the loop. */
- status = MQTTSuccess;
+
+ if( appCallback( pContext, pIncomingPacket, &deserializedInfo, NULL,
+ &pContext->ackPropsBuffer, NULL ) == false )
+ {
+ status = MQTTEventCallbackFailed;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t handleIncomingDisconnect( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTDeserializedInfo_t deserializedInfo = { 0 };
+ MQTTPropBuilder_t propBuffer = { 0 };
+ MQTTReasonCodeInfo_t reasonCode = { 0 };
+
+ assert( pContext != NULL );
+ assert( pContext->appCallback != NULL );
+ assert( pIncomingPacket != NULL );
+
+ status = MQTT_DeserializeDisconnect( pIncomingPacket,
+ pContext->connectionProperties.maxPacketSize,
+ &reasonCode,
+ &propBuffer );
+
+ if( status == MQTTSuccess )
+ {
+ deserializedInfo.pReasonCode = &reasonCode;
+
+ if( pContext->appCallback( pContext, pIncomingPacket, &deserializedInfo,
+ NULL, &pContext->ackPropsBuffer, &propBuffer ) == false )
+ {
+ status = MQTTEventCallbackFailed;
+ }
}
return status;
}
+
/*-----------------------------------------------------------*/
static MQTTStatus_t receiveSingleIteration( MQTTContext_t * pContext,
@@ -1731,135 +2243,203 @@ static MQTTStatus_t receiveSingleIteration( MQTTContext_t * pContext,
MQTTStatus_t status = MQTTSuccess;
MQTTPacketInfo_t incomingPacket = { 0 };
int32_t recvBytes;
- size_t totalMQTTPacketLength = 0;
+ uint32_t totalMQTTPacketLength = 0;
assert( pContext != NULL );
assert( pContext->networkBuffer.pBuffer != NULL );
+ /* We will store the result in a signed 32 bit value, so we cannot have a
+ * buffer bigger than what can fit in a int32_t. 0x7FFFFFFF is 2Gb which should
+ * be enough. */
+ assert( pContext->networkBuffer.size < 0x7FFFFFFF );
+
/* Read as many bytes as possible into the network buffer. */
recvBytes = pContext->transportInterface.recv( pContext->transportInterface.pNetworkContext,
&( pContext->networkBuffer.pBuffer[ pContext->index ] ),
pContext->networkBuffer.size - pContext->index );
- if( recvBytes < 0 )
+ LogDebug( ( "Received %ld bytes from network.",
+ ( long int ) recvBytes ) );
+ LogTrace( ( "Index is at location: %ld",
+ ( long int ) pContext->index ) );
+ LogTrace( ( "Remaining buffer capacity: %ld",
+ ( long int ) ( pContext->networkBuffer.size - pContext->index ) ) );
+
+ do
{
- /* The receive function has failed. Bubble up the error up to the user. */
- status = MQTTRecvFailed;
+ if( recvBytes < 0 )
+ {
+ /* The receive function has failed. Bubble up the error up to the user. */
+ status = MQTTRecvFailed;
- MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
- if( pContext->connectStatus == MQTTConnected )
+ if( pContext->connectStatus == MQTTConnected )
+ {
+ pContext->connectStatus = MQTTDisconnectPending;
+ }
+
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+
+ LogTrace( ( "Recv failed with error: %s", strerror( errno ) ) );
+ }
+ else if( ( recvBytes == 0 ) && ( pContext->index == 0U ) )
+ {
+ LogDebug( ( "No data available from the network." ) );
+
+ /* No more bytes available since the last read and neither is anything in
+ * the buffer. */
+ status = MQTTNoDataAvailable;
+ }
+
+ /* Either something was received, or there is still data to be processed in the
+ * buffer, or both. */
+ else
+ {
+ /* Update the number of bytes in the MQTT fixed buffer. */
+
+ /* No need to check whether the addition will overflow here since the transport
+ * interface is supposed to only return less than or equal number of bytes than
+ * requested. */
+ pContext->index += ( size_t ) recvBytes;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pContext->networkBuffer.pBuffer,
+ &( pContext->index ),
+ &incomingPacket );
+
+ /* Remaining length can be in the range of 0 -> MQTT_MAX_REMAINING_LENGTH.
+ * Thus, the addition will not overflow. */
+ totalMQTTPacketLength = incomingPacket.remainingLength + incomingPacket.headerLength;
+ }
+
+ /* No data was received, check for keep alive timeout. */
+ if( ( ( status == MQTTSuccess ) ||
+ ( status == MQTTNoDataAvailable ) ||
+ ( status == MQTTNeedMoreBytes ) ) &&
+ ( recvBytes == 0 ) )
+ {
+ if( manageKeepAlive == true )
+ {
+ /* Keep the copy of the status to be reset later. */
+ MQTTStatus_t statusCopy = status;
+
+ /* Assign status so an error can be bubbled up to application,
+ * but reset it on success. */
+ status = handleKeepAlive( pContext );
+
+ if( status == MQTTSuccess )
+ {
+ /* Reset the status. */
+ status = statusCopy;
+ }
+ else
+ {
+ LogError( ( "Handling of keep alive failed. Status=%s",
+ MQTT_Status_strerror( status ) ) );
+ }
+ }
+ }
+ else
+ {
+ recvBytes = 0;
+ }
+
+ /* Check whether there is data available before processing the packet further. */
+ if( ( status == MQTTNeedMoreBytes ) || ( status == MQTTNoDataAvailable ) )
+ {
+ /* Do nothing as there is nothing to be processed right now. The proper
+ * error code will be bubbled up to the user. */
+ }
+ /* Any other error code. */
+ else if( status != MQTTSuccess )
+ {
+ LogError( ( "Call to receiveSingleIteration failed. Status=%s",
+ MQTT_Status_strerror( status ) ) );
+ }
+ /* If the MQTT Packet size is bigger than the buffer itself. */
+ else if( totalMQTTPacketLength > pContext->networkBuffer.size )
+ {
+ LogError( ( "Incoming packet size is bigger than MQTT buffer size. Total packet length %" PRIu32,
+ totalMQTTPacketLength ) );
+ status = MQTTRecvFailed;
+ }
+ /* If the total packet is of more length than the bytes we have available. */
+ else if( totalMQTTPacketLength > pContext->index )
{
- pContext->connectStatus = MQTTDisconnectPending;
+ status = MQTTNeedMoreBytes;
}
-
- MQTT_POST_STATE_UPDATE_HOOK( pContext );
- }
- else if( ( recvBytes == 0 ) && ( pContext->index == 0U ) )
- {
- /* No more bytes available since the last read and neither is anything in
- * the buffer. */
- status = MQTTNoDataAvailable;
- }
-
- /* Either something was received, or there is still data to be processed in the
- * buffer, or both. */
- else
- {
- /* Update the number of bytes in the MQTT fixed buffer. */
- pContext->index += ( size_t ) recvBytes;
-
- status = MQTT_ProcessIncomingPacketTypeAndLength( pContext->networkBuffer.pBuffer,
- &( pContext->index ),
- &incomingPacket );
-
- totalMQTTPacketLength = incomingPacket.remainingLength + incomingPacket.headerLength;
- }
-
- /* No data was received, check for keep alive timeout. */
- if( recvBytes == 0 )
- {
- if( manageKeepAlive == true )
+ else
{
- /* Keep the copy of the status to be reset later. */
- MQTTStatus_t statusCopy = status;
+ /* MISRA else. */
+ }
- /* Assign status so an error can be bubbled up to application,
- * but reset it on success. */
- status = handleKeepAlive( pContext );
+ /* Handle received packet. If incomplete data was read then this will not execute. */
+ if( status == MQTTSuccess )
+ {
+ incomingPacket.pRemainingData = &pContext->networkBuffer.pBuffer[ incomingPacket.headerLength ];
- if( status == MQTTSuccess )
+ /* PUBLISH packets allow flags in the lower four bits. For other
+ * packet types, they are reserved. */
+ if( ( incomingPacket.type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH )
{
- /* Reset the status. */
- status = statusCopy;
+ status = handleIncomingPublish( pContext, &incomingPacket );
}
- else
+ else if( incomingPacket.type == MQTT_PACKET_TYPE_DISCONNECT )
{
- LogError( ( "Handling of keep alive failed. Status=%s",
- MQTT_Status_strerror( status ) ) );
- }
- }
- }
+ status = handleIncomingDisconnect( pContext, &incomingPacket );
- /* Check whether there is data available before processing the packet further. */
- if( ( status == MQTTNeedMoreBytes ) || ( status == MQTTNoDataAvailable ) )
- {
- /* Do nothing as there is nothing to be processed right now. The proper
- * error code will be bubbled up to the user. */
- }
- /* Any other error code. */
- else if( status != MQTTSuccess )
- {
- LogError( ( "Call to receiveSingleIteration failed. Status=%s",
- MQTT_Status_strerror( status ) ) );
- }
- /* If the MQTT Packet size is bigger than the buffer itself. */
- else if( totalMQTTPacketLength > pContext->networkBuffer.size )
- {
- /* Discard the packet from the receive buffer and drain the pending
- * data from the socket buffer. */
- status = discardStoredPacket( pContext,
- &incomingPacket );
- }
- /* If the total packet is of more length than the bytes we have available. */
- else if( totalMQTTPacketLength > pContext->index )
- {
- status = MQTTNeedMoreBytes;
- }
- else
- {
- /* MISRA else. */
- }
+ if( status == MQTTSuccess )
+ {
+ LogInfo( ( "Disconnected from the broker." ) );
+ }
+ else if( status != MQTTEventCallbackFailed )
+ {
+ /* Incoming packet is malformed at this stage. */
+ MQTTSuccessFailReasonCode_t reason = MQTT_REASON_DISCONNECT_MALFORMED_PACKET;
+ status = MQTT_Disconnect( pContext, NULL, &reason );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Failed to send disconnect following a malformed disconnect "
+ "from the server. coreMQTT will forcefully disconnect now." ) );
+ }
+ else
+ {
+ status = MQTTStatusNotConnected;
+ }
+ }
+ else /* At this point the callback has failed. */
+ {
+ /* TODO: If handling fails, the packet should be
+ * resent to the application or not? */
+ }
- /* Handle received packet. If incomplete data was read then this will not execute. */
- if( status == MQTTSuccess )
- {
- incomingPacket.pRemainingData = &pContext->networkBuffer.pBuffer[ incomingPacket.headerLength ];
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
+ pContext->connectStatus = MQTTNotConnected;
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+ }
+ else
+ {
+ status = handleIncomingAck( pContext, &incomingPacket, manageKeepAlive );
- /* PUBLISH packets allow flags in the lower four bits. For other
- * packet types, they are reserved. */
- if( ( incomingPacket.type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH )
- {
- status = handleIncomingPublish( pContext, &incomingPacket );
- }
- else
- {
- status = handleIncomingAck( pContext, &incomingPacket, manageKeepAlive );
- }
+ /* TODO: decide what to do when the app callback has failed.
+ * Should the packet be re-sent to the app? */
+ }
- /* Update the index to reflect the remaining bytes in the buffer. */
- pContext->index -= totalMQTTPacketLength;
+ if( status == MQTTSuccess )
+ {
+ /* Update the index to reflect the remaining bytes in the buffer. */
+ pContext->index -= totalMQTTPacketLength;
- /* Move the remaining bytes to the front of the buffer. */
- ( void ) memmove( pContext->networkBuffer.pBuffer,
- &( pContext->networkBuffer.pBuffer[ totalMQTTPacketLength ] ),
- pContext->index );
+ /* Move the remaining bytes to the front of the buffer. */
+ ( void ) memmove( pContext->networkBuffer.pBuffer,
+ &( pContext->networkBuffer.pBuffer[ totalMQTTPacketLength ] ),
+ pContext->index );
- if( status == MQTTSuccess )
- {
- pContext->lastPacketRxTime = pContext->getTime();
+ pContext->lastPacketRxTime = pContext->getTime();
+ }
}
- }
+ } while( ( pContext->index > 0 ) && ( status == MQTTSuccess ) );
if( status == MQTTNoDataAvailable )
{
@@ -1876,7 +2456,8 @@ static MQTTStatus_t receiveSingleIteration( MQTTContext_t * pContext,
static MQTTStatus_t validateSubscribeUnsubscribeParams( const MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId )
+ uint16_t packetId,
+ MQTTSubscriptionType_t subscriptionType )
{
MQTTStatus_t status = MQTTSuccess;
size_t iterator;
@@ -1904,19 +2485,27 @@ static MQTTStatus_t validateSubscribeUnsubscribeParams( const MQTTContext_t * pC
{
if( pContext->incomingPublishRecords == NULL )
{
- for( iterator = 0; iterator < subscriptionCount; iterator++ )
+ for( iterator = 0U; iterator < subscriptionCount; iterator++ )
{
if( pSubscriptionList[ iterator ].qos > MQTTQoS0 )
{
LogError( ( "The incoming publish record list is not "
"initialised for QoS1/QoS2 records. Please call "
- " MQTT_InitStatefulQoS to enable use of QoS1 and "
- " QoS2 packets." ) );
+ "MQTT_InitStatefulQoS to enable use of QoS1 and "
+ "QoS2 packets." ) );
status = MQTTBadParameter;
break;
}
}
}
+
+ if( status == MQTTSuccess )
+ {
+ for( iterator = 0U; iterator < subscriptionCount; iterator++ )
+ {
+ status = validateTopicFilter( pContext, pSubscriptionList, iterator, subscriptionType );
+ }
+ }
}
return status;
@@ -1928,9 +2517,9 @@ static size_t addEncodedStringToVector( uint8_t serializedLength[ CORE_MQTT_SERI
const char * const string,
uint16_t length,
TransportOutVector_t * iterator,
- size_t * updatedLength )
+ uint32_t * updatedLength )
{
- size_t packetLength = 0U;
+ uint32_t packetLength = 0U;
TransportOutVector_t * pLocalIterator = iterator;
size_t vectorsAdded = 0U;
@@ -1968,48 +2557,100 @@ static MQTTStatus_t sendSubscribeWithoutCopy( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength )
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
uint8_t * pIndex;
+
+ /**
+ * Fixed Size Properties
+ */
TransportOutVector_t pIoVector[ MQTT_SUB_UNSUB_MAX_VECTORS ];
TransportOutVector_t * pIterator;
uint8_t serializedTopicFieldLength[ MQTT_SUB_UNSUB_MAX_VECTORS ][ CORE_MQTT_SERIALIZED_LENGTH_FIELD_BYTES ];
- size_t totalPacketLength = 0U;
+ uint8_t subscriptionOptionsArray[ MQTT_SUB_UNSUB_MAX_VECTORS / CORE_MQTT_SUBSCRIBE_PER_TOPIC_VECTOR_LENGTH ];
+ uint32_t totalPacketLength = 0U;
size_t ioVectorLength = 0U;
size_t subscriptionsSent = 0U;
- size_t vectorsAdded;
+ size_t vectorsAdded = 0U;
size_t topicFieldLengthIndex;
+ uint32_t subscribePropLen = 0;
+ size_t currentOptionIndex = 0U;
+
+ /**
+ * Maximum number of bytes by the fixed header of a SUBSCRIBE packet.
+ * MQTT Control Byte 0 + 1 = 1
+ * Remaining Length + 4 = 5
+ * Packet Id + 2 = 7
+ */
+ uint8_t subscribeHeader[ 7U ];
- /* Maximum number of bytes required by the 'fixed' part of the SUBSCRIBE
- * packet header according to the MQTT specification.
- * MQTT Control Byte 0 + 1 = 1
- * Remaining length (max) + 4 = 5
- * Packet ID + 2 = 7 */
- uint8_t subscribeheader[ 7U ];
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
- /* The vector array should be at least three element long as the topic
- * string needs these many vector elements to be stored. */
- assert( MQTT_SUB_UNSUB_MAX_VECTORS >= CORE_MQTT_SUBSCRIBE_PER_TOPIC_VECTOR_LENGTH );
+ assert( pContext != NULL );
+ assert( pSubscriptionList != NULL );
- pIndex = subscribeheader;
+ pIndex = subscribeHeader;
pIterator = pIoVector;
- pIndex = MQTT_SerializeSubscribeHeader( remainingLength,
- pIndex,
- packetId );
+ pIndex = serializeSubscribeHeader( remainingLength, pIndex, packetId );
+ assert( ( pIndex - subscribeHeader ) <= 7 );
+
+ pIterator->iov_base = subscribeHeader;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pIterator->iov_len = ( size_t ) ( pIndex - subscribeHeader );
+
+ totalPacketLength += pIterator->iov_len;
+ pIterator++;
+ ioVectorLength++;
+
+ /**
+ * Sending Property Buffer
+ */
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) &&
+ ( pPropertyBuilder->currentIndex < MQTT_REMAINING_LENGTH_INVALID ) );
+ subscribePropLen = pPropertyBuilder->currentIndex;
+ }
- /* The header is to be sent first. */
- pIterator->iov_base = subscribeheader;
+ pIndex = encodeVariableLength( propertyLength, subscribePropLen );
+ pIterator->iov_base = propertyLength;
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
/* coverity[misra_c_2012_rule_18_2_violation] */
/* coverity[misra_c_2012_rule_10_8_violation] */
- pIterator->iov_len = ( size_t ) ( pIndex - subscribeheader );
+ pIterator->iov_len = ( size_t ) ( pIndex - propertyLength );
totalPacketLength += pIterator->iov_len;
pIterator++;
ioVectorLength++;
+ if( subscribePropLen > 0U )
+ {
+ pIterator->iov_base = pPropertyBuilder->pBuffer;
+ pIterator->iov_len = pPropertyBuilder->currentIndex;
+
+ if( ADDITION_WILL_OVERFLOW_U32( totalPacketLength, ( uint32_t ) pIterator->iov_len ) )
+ {
+ LogError( ( "MQTT packet size must be less than 268435461. Adding properties will overflow the limit." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalPacketLength += pIterator->iov_len;
+ pIterator++;
+ ioVectorLength++;
+ }
+ }
+
while( ( status == MQTTSuccess ) && ( subscriptionsSent < subscriptionCount ) )
{
/* Reset the index for next iteration. */
@@ -2020,7 +2661,16 @@ static MQTTStatus_t sendSubscribeWithoutCopy( MQTTContext_t * pContext,
while( ( ioVectorLength <= ( MQTT_SUB_UNSUB_MAX_VECTORS - CORE_MQTT_SUBSCRIBE_PER_TOPIC_VECTOR_LENGTH ) ) &&
( subscriptionsSent < subscriptionCount ) )
{
- /* The topic filter and the filter length gets sent next. */
+ if( ADDITION_WILL_OVERFLOW_U32( totalPacketLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalPacketLength + 2U, pSubscriptionList[ subscriptionsSent ].topicFilterLength ) ||
+ ( ( totalPacketLength + 2U + pSubscriptionList[ subscriptionsSent ].topicFilterLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ break;
+ }
+
+ /* The topic filter and the filter length gets sent next. (filter length - 2 bytes , topic filter - utf - 8 ) */
vectorsAdded = addEncodedStringToVector( serializedTopicFieldLength[ topicFieldLengthIndex ],
pSubscriptionList[ subscriptionsSent ].pTopicFilter,
pSubscriptionList[ subscriptionsSent ].topicFilterLength,
@@ -2029,38 +2679,48 @@ static MQTTStatus_t sendSubscribeWithoutCopy( MQTTContext_t * pContext,
/* Update the pointer after the above operation. */
pIterator = &pIterator[ vectorsAdded ];
+ ioVectorLength += vectorsAdded;
- /* Lastly, the QoS gets sent. */
- pIterator->iov_base = &( pSubscriptionList[ subscriptionsSent ].qos );
- pIterator->iov_len = 1U;
- totalPacketLength += pIterator->iov_len;
+ /* Lastly, send the subscription options. */
+ addSubscriptionOptions( pSubscriptionList[ subscriptionsSent ],
+ subscriptionOptionsArray,
+ currentOptionIndex );
- /* Increment the pointer. */
+ pIterator->iov_base = &( subscriptionOptionsArray[ currentOptionIndex ] );
+ pIterator->iov_len = 1U;
+ totalPacketLength += 1U;
pIterator++;
-
- /* Two slots get used by the topic string length and topic string.
- * One slot gets used by the quality of service. */
- ioVectorLength += vectorsAdded + 1U;
+ ioVectorLength++;
+ currentOptionIndex++;
subscriptionsSent++;
-
- /* The index needs to be updated for next iteration. */
topicFieldLengthIndex++;
}
- if( sendMessageVector( pContext,
- pIoVector,
- ioVectorLength ) != ( int32_t ) totalPacketLength )
+ if( ( status == MQTTSuccess ) && ( totalPacketLength > MQTT_MAX_PACKET_SIZE ) )
{
- status = MQTTSendFailed;
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
}
- /* Update the iterator for the next potential loop iteration. */
- pIterator = pIoVector;
- /* Reset the vector length for the next potential loop iteration. */
- ioVectorLength = 0U;
- /* Reset the packet length for the next potential loop iteration. */
- totalPacketLength = 0U;
+ if( status == MQTTSuccess )
+ {
+ if( sendMessageVector( pContext, pIoVector, ioVectorLength ) != ( int32_t ) totalPacketLength )
+ {
+ LogError( ( "Error in sending SUBSCRIBE packet" ) );
+ status = MQTTSendFailed;
+ }
+
+ /* Update the iterator for the next potential loop iteration. */
+ pIterator = pIoVector;
+
+ /* Reset the vector length for the next potential loop iteration. */
+ ioVectorLength = 0U;
+ /* Reset the packet length for the next potential loop iteration. */
+ totalPacketLength = 0U;
+ /* Reset index of the subscriptionOptionsArray for the next potential loop iteration. */
+ currentOptionIndex = 0U;
+ }
}
return status;
@@ -2072,65 +2732,122 @@ static MQTTStatus_t sendUnsubscribeWithoutCopy( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength )
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
uint8_t * pIndex;
+
+ /**
+ * Fixed Size Properties
+ */
TransportOutVector_t pIoVector[ MQTT_SUB_UNSUB_MAX_VECTORS ];
TransportOutVector_t * pIterator;
uint8_t serializedTopicFieldLength[ MQTT_SUB_UNSUB_MAX_VECTORS ][ CORE_MQTT_SERIALIZED_LENGTH_FIELD_BYTES ];
- size_t totalPacketLength = 0U;
- size_t unsubscriptionsSent = 0U;
+ uint32_t totalPacketLength = 0U;
size_t ioVectorLength = 0U;
- size_t vectorsAdded;
+ size_t unsubscriptionsSent = 0U;
+ size_t vectorsAdded = 0U;
size_t topicFieldLengthIndex;
+ size_t unsubscribePropLen = 0U;
- /* Maximum number of bytes required by the 'fixed' part of the UNSUBSCRIBE
- * packet header according to the MQTT specification.
- * MQTT Control Byte 0 + 1 = 1
- * Remaining length (max) + 4 = 5
- * Packet ID + 2 = 7 */
- uint8_t unsubscribeheader[ 7U ];
+ /**
+ * Maximum number of bytes by the fixed header of a SUBSCRIBE packet.
+ * MQTT Control Byte 0 + 1 = 1
+ * Remaining Length + 4 = 5
+ * Packet Id + 2 = 7
+ */
+ uint8_t unsubscribeHeader[ 7U ];
- /* The vector array should be at least three element long as the topic
- * string needs these many vector elements to be stored. */
- assert( MQTT_SUB_UNSUB_MAX_VECTORS >= CORE_MQTT_UNSUBSCRIBE_PER_TOPIC_VECTOR_LENGTH );
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
- pIndex = unsubscribeheader;
+ pIndex = unsubscribeHeader;
pIterator = pIoVector;
- pIndex = MQTT_SerializeUnsubscribeHeader( remainingLength,
- pIndex,
- packetId );
+ pIndex = serializeUnsubscribeHeader( remainingLength, pIndex, packetId );
+
+ pIterator->iov_base = unsubscribeHeader;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pIterator->iov_len = ( size_t ) ( pIndex - unsubscribeHeader );
+ assert( pIterator->iov_len <= 7 );
+
+ totalPacketLength += pIterator->iov_len;
+ pIterator++;
+ ioVectorLength++;
+
+ /**
+ * Sending Property Buffer
+ */
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ unsubscribePropLen = pPropertyBuilder->currentIndex;
+ }
- /* The header is to be sent first. */
- pIterator->iov_base = unsubscribeheader;
+ pIndex = encodeVariableLength( propertyLength, unsubscribePropLen );
+ pIterator->iov_base = propertyLength;
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
/* coverity[misra_c_2012_rule_18_2_violation] */
/* coverity[misra_c_2012_rule_10_8_violation] */
- pIterator->iov_len = ( size_t ) ( pIndex - unsubscribeheader );
+ pIterator->iov_len = ( size_t ) ( pIndex - propertyLength );
totalPacketLength += pIterator->iov_len;
pIterator++;
ioVectorLength++;
+ if( unsubscribePropLen > 0U )
+ {
+ pIterator->iov_base = pPropertyBuilder->pBuffer;
+ pIterator->iov_len = pPropertyBuilder->currentIndex;
+
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pIterator->iov_len ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalPacketLength, ( uint32_t ) pIterator->iov_len ) ||
+ ( ( totalPacketLength + pIterator->iov_len ) > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Total packet length must less than 268435461." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalPacketLength += pIterator->iov_len;
+ pIterator++;
+ ioVectorLength++;
+ }
+ }
+
while( ( status == MQTTSuccess ) && ( unsubscriptionsSent < subscriptionCount ) )
{
/* Reset the index for next iteration. */
topicFieldLengthIndex = 0;
- /* Check whether the subscription topic will fit in the given vector. */
+ /* Check whether the subscription topic (with QoS) will fit in the
+ * given vector. */
while( ( ioVectorLength <= ( MQTT_SUB_UNSUB_MAX_VECTORS - CORE_MQTT_UNSUBSCRIBE_PER_TOPIC_VECTOR_LENGTH ) ) &&
( unsubscriptionsSent < subscriptionCount ) )
{
- /* The topic filter gets sent next. */
+ if( ADDITION_WILL_OVERFLOW_U32( totalPacketLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalPacketLength + 2U, pSubscriptionList[ unsubscriptionsSent ].topicFilterLength ) ||
+ ( ( totalPacketLength + 2U + pSubscriptionList[ unsubscriptionsSent ].topicFilterLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ break;
+ }
+
+ /* The topic filter and the filter length gets sent next. (filter length - 2 bytes , topic filter - utf8 ) */
vectorsAdded = addEncodedStringToVector( serializedTopicFieldLength[ topicFieldLengthIndex ],
pSubscriptionList[ unsubscriptionsSent ].pTopicFilter,
pSubscriptionList[ unsubscriptionsSent ].topicFilterLength,
pIterator,
&totalPacketLength );
- /* Update the iterator to point to the next empty location. */
+ /* Update the pointer after the above operation. */
pIterator = &pIterator[ vectorsAdded ];
/* Update the total count based on how many vectors were added. */
ioVectorLength += vectorsAdded;
@@ -2141,17 +2858,27 @@ static MQTTStatus_t sendUnsubscribeWithoutCopy( MQTTContext_t * pContext,
topicFieldLengthIndex++;
}
- if( sendMessageVector( pContext, pIoVector, ioVectorLength ) != ( int32_t ) totalPacketLength )
+ if( totalPacketLength > MQTT_MAX_PACKET_SIZE )
{
- status = MQTTSendFailed;
+ LogError( ( "Total MQTT packet size must be less than 268435461." ) );
+ status = MQTTBadParameter;
}
- /* Update the iterator for the next potential loop iteration. */
- pIterator = pIoVector;
- /* Reset the vector length for the next potential loop iteration. */
- ioVectorLength = 0U;
- /* Reset the packet length for the next potential loop iteration. */
- totalPacketLength = 0U;
+ if( status == MQTTSuccess )
+ {
+ if( sendMessageVector( pContext, pIoVector, ioVectorLength ) != ( int32_t ) totalPacketLength )
+ {
+ LogError( ( "Error in sending UNSUBSCRIBE packet" ) );
+ status = MQTTSendFailed;
+ }
+
+ /* Update the iterator for the next potential loop iteration. */
+ pIterator = pIoVector;
+ /* Reset the vector length for the next potential loop iteration. */
+ ioVectorLength = 0U;
+ /* Reset the packet length for the next potential loop iteration. */
+ totalPacketLength = 0U;
+ }
}
return status;
@@ -2163,24 +2890,42 @@ static MQTTStatus_t sendPublishWithoutCopy( MQTTContext_t * pContext,
const MQTTPublishInfo_t * pPublishInfo,
uint8_t * pMqttHeader,
size_t headerSize,
- uint16_t packetId )
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
size_t ioVectorLength;
- size_t totalMessageLength;
+ uint32_t totalMessageLength;
+ size_t publishPropLength = 0U;
bool dupFlagChanged = false;
/* Bytes required to encode the packet ID in an MQTT header according to
* the MQTT specification. */
uint8_t serializedPacketID[ 2U ];
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
+
/* Maximum number of vectors required to encode and send a publish
* packet. The breakdown is shown below.
* Fixed header (including topic string length) 0 + 1 = 1
* Topic string + 1 = 2
* Packet ID (only when QoS > QoS0) + 1 = 3
- * Payload + 1 = 4 */
- TransportOutVector_t pIoVector[ 4U ];
+ * Property Length + 1 = 4
+ * Optional Properties + 1 = 5
+ * Payload + 1 = 6 */
+
+ TransportOutVector_t pIoVector[ 6U ];
+ uint8_t * pIndex;
+ TransportOutVector_t * iterator;
+
+ assert( pContext != NULL );
+ assert( pPublishInfo != NULL );
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) );
+ assert( headerSize <= 7U );
/* The header is sent first. */
pIoVector[ 0U ].iov_base = pMqttHeader;
@@ -2209,18 +2954,67 @@ static MQTTStatus_t sendPublishWithoutCopy( MQTTContext_t * pContext,
totalMessageLength += sizeof( serializedPacketID );
}
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ publishPropLength = pPropertyBuilder->currentIndex;
+ }
+
+ iterator = &pIoVector[ ioVectorLength ];
+ pIndex = propertyLength;
+ pIndex = encodeVariableLength( pIndex, publishPropLength );
+ iterator->iov_base = propertyLength;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - propertyLength );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ /* Serialize the publish properties, if provided. */
+ if( publishPropLength > 0U )
+ {
+ iterator->iov_base = pPropertyBuilder->pBuffer;
+ iterator->iov_len = pPropertyBuilder->currentIndex;
+
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength, pPropertyBuilder->currentIndex ) ||
+ ( ( totalMessageLength + pPropertyBuilder->currentIndex ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+ }
+ }
+
/* Publish packets are allowed to contain no payload. */
- if( pPublishInfo->payloadLength > 0U )
+ if( ( status == MQTTSuccess ) && ( pPublishInfo->payloadLength > 0U ) )
{
pIoVector[ ioVectorLength ].iov_base = pPublishInfo->pPayload;
pIoVector[ ioVectorLength ].iov_len = pPublishInfo->payloadLength;
- ioVectorLength++;
- totalMessageLength += pPublishInfo->payloadLength;
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, pPublishInfo->payloadLength ) ||
+ ( ( totalMessageLength + pPublishInfo->payloadLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ ioVectorLength++;
+ totalMessageLength += pPublishInfo->payloadLength;
+ }
}
- /* store a copy of the publish for retransmission purposes */
- if( ( pPublishInfo->qos > MQTTQoS0 ) &&
+ /* Store a copy of the publish for retransmission purposes. */
+ if( ( status == MQTTSuccess ) &&
+ ( pPublishInfo->qos > MQTTQoS0 ) &&
( pContext->storeFunction != NULL ) )
{
/* If not already set, set the dup flag before storing a copy of the publish
@@ -2268,41 +3062,61 @@ static MQTTStatus_t sendPublishWithoutCopy( MQTTContext_t * pContext,
static MQTTStatus_t sendConnectWithoutCopy( MQTTContext_t * pContext,
const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength )
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTPropBuilder_t * pWillPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
TransportOutVector_t * iterator;
size_t ioVectorLength = 0U;
- size_t totalMessageLength = 0U;
+ uint32_t totalMessageLength = 0U;
+ uint32_t connectPropLen = 0U;
int32_t bytesSentOrError;
uint8_t * pIndex;
- uint8_t serializedClientIDLength[ 2 ];
- uint8_t serializedTopicLength[ 2 ];
- uint8_t serializedPayloadLength[ 2 ];
- uint8_t serializedUsernameLength[ 2 ];
- uint8_t serializedPasswordLength[ 2 ];
+ uint8_t serializedClientIDLength[ 2U ];
+ uint8_t serializedTopicLength[ 2U ];
+ uint8_t serializedPayloadLength[ 2U ];
+ uint8_t serializedUsernameLength[ 2U ];
+ uint8_t serializedPasswordLength[ 2U ];
+
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
+ uint8_t willPropertyLength[ 4U ];
size_t vectorsAdded;
- /* Maximum number of bytes required by the 'fixed' part of the CONNECT
+ /* Maximum number of bytes required by the fixed part of the CONNECT
* packet header according to the MQTT specification.
- * MQTT Control Byte 0 + 1 = 1
- * Remaining length (max) + 4 = 5
- * Protocol Name Length + 2 = 7
- * Protocol Name (MQTT) + 4 = 11
- * Protocol level + 1 = 12
- * Connect flags + 1 = 13
- * Keep alive + 2 = 15 */
+ * MQTT Control Byte 0 + 1 = 1
+ * Remaining length (max) + 4 = 5
+ * Protocol Name Length + 2 = 7
+ * Protocol Name (MQTT) + 4 = 11
+ * Protocol level + 1 = 12
+ * Connect flags + 1 = 13
+ * Keep alive + 2 = 15
+ */
+
uint8_t connectPacketHeader[ 15U ];
/* The maximum vectors required to encode and send a connect packet. The
* breakdown is shown below.
* Fixed header 0 + 1 = 1
- * Client ID + 2 = 3
- * Will topic + 2 = 5
- * Will payload + 2 = 7
- * Username + 2 = 9
- * Password + 2 = 11 */
- TransportOutVector_t pIoVector[ 11U ];
+ * Connect Properties + 2 = 3
+ * Client ID + 2 = 5
+ * Will Properties + 2 = 7
+ * Will topic + 2 = 9
+ * Will payload + 2 = 11
+ * Username + 2 = 13
+ * Password + 2 = 15
+ */
+ TransportOutVector_t pIoVector[ 15U ];
+
+ if( pWillInfo != NULL )
+ {
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pWillInfo->topicNameLength ) );
+ }
iterator = pIoVector;
pIndex = connectPacketHeader;
@@ -2315,94 +3129,251 @@ static MQTTStatus_t sendConnectWithoutCopy( MQTTContext_t * pContext,
}
else
{
- pIndex = MQTT_SerializeConnectFixedHeader( pIndex,
- pConnectInfo,
- pWillInfo,
- remainingLength );
+ pIndex = serializeConnectFixedHeader( pIndex,
+ pConnectInfo,
+ pWillInfo,
+ remainingLength );
- assert( ( ( size_t ) ( pIndex - connectPacketHeader ) ) <= sizeof( connectPacketHeader ) );
+ /**
+ * Set value of serverKeepAlive to keepAlive value sent in the CONNECT packet.
+ * This value shall be overwritten if the broker also sends a Keep Alive Interval
+ * in the CONNACK.
+ */
+ pContext->connectionProperties.serverKeepAlive = pConnectInfo->keepAliveSeconds;
- /* The header gets sent first. */
iterator->iov_base = connectPacketHeader;
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
/* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
/* coverity[misra_c_2012_rule_18_2_violation] */
/* coverity[misra_c_2012_rule_10_8_violation] */
iterator->iov_len = ( size_t ) ( pIndex - connectPacketHeader );
+
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) );
+ assert( pPropertyBuilder->currentIndex < MQTT_REMAINING_LENGTH_INVALID );
+
+ connectPropLen = pPropertyBuilder->currentIndex;
+ }
+
+ pIndex = encodeVariableLength( propertyLength, connectPropLen );
+ iterator->iov_base = propertyLength;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - propertyLength );
totalMessageLength += iterator->iov_len;
iterator++;
ioVectorLength++;
- /* Serialize the client ID. */
- vectorsAdded = addEncodedStringToVector( serializedClientIDLength,
- pConnectInfo->pClientIdentifier,
- pConnectInfo->clientIdentifierLength,
- iterator,
- &totalMessageLength );
+ /* Serialize CONNECT properties, if present. */
+ if( connectPropLen > 0U )
+ {
+ iterator->iov_base = pPropertyBuilder->pBuffer;
+ iterator->iov_len = pPropertyBuilder->currentIndex;
+
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, iterator->iov_len ) ||
+ ( ( totalMessageLength + iterator->iov_len ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ /* Update the context with properties that will persist for the entire connection. */
+ status = updateContextWithConnectProps( pPropertyBuilder, &pContext->connectionProperties );
+ }
+ }
- /* Update the iterator to point to the next empty slot. */
- iterator = &iterator[ vectorsAdded ];
- ioVectorLength += vectorsAdded;
+ if( status == MQTTSuccess )
+ {
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength + 2U, pConnectInfo->clientIdentifierLength ) ||
+ ( ( totalMessageLength + 2U + pConnectInfo->clientIdentifierLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Serialize the client ID. */
+ vectorsAdded = addEncodedStringToVector( serializedClientIDLength,
+ pConnectInfo->pClientIdentifier,
+ pConnectInfo->clientIdentifierLength,
+ iterator,
+ &totalMessageLength );
+
+ /* Update the iterator to point to the next empty slot. */
+ iterator = &iterator[ vectorsAdded ];
+ ioVectorLength += vectorsAdded;
+ }
+ }
- if( pWillInfo != NULL )
+ if( ( status == MQTTSuccess ) && ( pWillInfo != NULL ) )
{
- /* Serialize the topic. */
- vectorsAdded = addEncodedStringToVector( serializedTopicLength,
- pWillInfo->pTopicName,
- pWillInfo->topicNameLength,
- iterator,
- &totalMessageLength );
+ uint32_t willPropsLen = 0U;
+
+ if( ( pWillPropertyBuilder != NULL ) && ( pWillPropertyBuilder->pBuffer != NULL ) )
+ {
+ willPropsLen = pWillPropertyBuilder->currentIndex;
+ }
+
+ pIndex = encodeVariableLength( willPropertyLength, willPropsLen );
+ iterator->iov_base = willPropertyLength;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - willPropertyLength );
+
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, iterator->iov_len ) ||
+ ( ( totalMessageLength + iterator->iov_len ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+ }
+
+ if( ( status == MQTTSuccess ) && ( willPropsLen > 0U ) )
+ {
+ /* Serialize the will properties, if present. */
+
+ iterator->iov_base = pWillPropertyBuilder->pBuffer;
+ iterator->iov_len = pWillPropertyBuilder->currentIndex;
- /* Update the iterator to point to the next empty slot. */
- iterator = &iterator[ vectorsAdded ];
- ioVectorLength += vectorsAdded;
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pWillPropertyBuilder->currentIndex ) );
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, iterator->iov_len ) ||
+ ( ( totalMessageLength + iterator->iov_len ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+ }
+ }
- /* Serialize the payload. Payload of last will and testament can be NULL. */
- vectorsAdded = addEncodedStringToVector( serializedPayloadLength,
- pWillInfo->pPayload,
- ( uint16_t ) pWillInfo->payloadLength,
- iterator,
- &totalMessageLength );
+ if( status == MQTTSuccess )
+ {
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength + 2U, pWillInfo->topicNameLength ) ||
+ ( ( totalMessageLength + 2U + pWillInfo->topicNameLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Serialize the topic. */
+ vectorsAdded = addEncodedStringToVector( serializedTopicLength,
+ pWillInfo->pTopicName,
+ pWillInfo->topicNameLength,
+ iterator,
+ &totalMessageLength );
+
+ /* Update the iterator to point to the next empty slot. */
+ iterator = &iterator[ vectorsAdded ];
+ ioVectorLength += vectorsAdded;
+ }
- /* Update the iterator to point to the next empty slot. */
- iterator = &iterator[ vectorsAdded ];
- ioVectorLength += vectorsAdded;
+ if( ( status == MQTTSuccess ) &&
+ ( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength + 2U, pWillInfo->payloadLength ) ||
+ ( ( totalMessageLength + 2U + pWillInfo->payloadLength ) > MQTT_MAX_PACKET_SIZE ) ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Serialize the payload. Payload of last will and testament can be NULL. */
+ vectorsAdded = addEncodedStringToVector( serializedPayloadLength,
+ pWillInfo->pPayload,
+ ( uint16_t ) pWillInfo->payloadLength,
+ iterator,
+ &totalMessageLength );
+
+ /* Update the iterator to point to the next empty slot. */
+ iterator = &iterator[ vectorsAdded ];
+ ioVectorLength += vectorsAdded;
+ }
+ }
}
/* Encode the user name if provided. */
- if( pConnectInfo->pUserName != NULL )
+ if( ( status == MQTTSuccess ) && ( pConnectInfo->pUserName != NULL ) )
{
- /* Serialize the user name string. */
- vectorsAdded = addEncodedStringToVector( serializedUsernameLength,
- pConnectInfo->pUserName,
- pConnectInfo->userNameLength,
- iterator,
- &totalMessageLength );
-
- /* Update the iterator to point to the next empty slot. */
- iterator = &iterator[ vectorsAdded ];
- ioVectorLength += vectorsAdded;
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength + 2U, pConnectInfo->userNameLength ) ||
+ ( ( totalMessageLength + 2U + pConnectInfo->userNameLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Serialize the user name string. */
+ vectorsAdded = addEncodedStringToVector( serializedUsernameLength,
+ pConnectInfo->pUserName,
+ pConnectInfo->userNameLength,
+ iterator,
+ &totalMessageLength );
+
+ /* Update the iterator to point to the next empty slot. */
+ iterator = &iterator[ vectorsAdded ];
+ ioVectorLength += vectorsAdded;
+ }
}
/* Encode the password if provided. */
- if( pConnectInfo->pPassword != NULL )
- {
- /* Serialize the user name string. */
- vectorsAdded = addEncodedStringToVector( serializedPasswordLength,
- pConnectInfo->pPassword,
- pConnectInfo->passwordLength,
- iterator,
- &totalMessageLength );
- /* Update the iterator to point to the next empty slot. */
- ioVectorLength += vectorsAdded;
+ if( ( status == MQTTSuccess ) && ( pConnectInfo->pPassword != NULL ) )
+ {
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, 2U ) ||
+ ADDITION_WILL_OVERFLOW_U32( totalMessageLength + 2U, pConnectInfo->passwordLength ) ||
+ ( ( totalMessageLength + 2U + pConnectInfo->passwordLength ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Serialize the user name string. */
+ vectorsAdded = addEncodedStringToVector( serializedPasswordLength,
+ pConnectInfo->pPassword,
+ pConnectInfo->passwordLength,
+ iterator,
+ &totalMessageLength );
+ /* Update the iterator to point to the next empty slot. */
+ ioVectorLength += vectorsAdded;
+ }
}
- bytesSentOrError = sendMessageVector( pContext, pIoVector, ioVectorLength );
-
- if( bytesSentOrError != ( int32_t ) totalMessageLength )
+ if( status == MQTTSuccess )
{
- status = MQTTSendFailed;
+ bytesSentOrError = sendMessageVector( pContext, pIoVector, ioVectorLength );
+
+ if( bytesSentOrError != ( int32_t ) totalMessageLength )
+ {
+ status = MQTTSendFailed;
+ }
}
}
@@ -2419,9 +3390,11 @@ static MQTTStatus_t receiveConnack( MQTTContext_t * pContext,
{
MQTTStatus_t status = MQTTSuccess;
MQTTGetCurrentTimeFunc_t getTimeStamp = NULL;
- uint32_t entryTimeMs = 0U, remainingTimeMs = 0U, timeTakenMs = 0U;
+ uint32_t entryTimeMs = 0U;
bool breakFromLoop = false;
uint16_t loopCount = 0U;
+ MQTTDeserializedInfo_t deserializedInfo = { 0 };
+ MQTTPropBuilder_t propBuffer = { 0 };
assert( pContext != NULL );
assert( pIncomingPacket != NULL );
@@ -2457,7 +3430,7 @@ static MQTTStatus_t receiveConnack( MQTTContext_t * pContext,
}
else
{
- breakFromLoop = loopCount >= MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT;
+ breakFromLoop = ( loopCount >= MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT );
loopCount++;
}
@@ -2466,29 +3439,16 @@ static MQTTStatus_t receiveConnack( MQTTContext_t * pContext,
if( status == MQTTSuccess )
{
- /* Time taken in this function so far. */
- timeTakenMs = calculateElapsedTime( getTimeStamp(), entryTimeMs );
-
- if( timeTakenMs < timeoutMs )
- {
- /* Calculate remaining time for receiving the remainder of
- * the packet. */
- remainingTimeMs = timeoutMs - timeTakenMs;
- }
-
/* Reading the remainder of the packet by transport recv.
* Attempt to read once even if the timeout has expired.
- * Invoking receivePacket with remainingTime as 0 would attempt to
- * recv from network once. If using retries, the remainder of the
- * CONNACK packet is tried to be read only once. Reading once would be
- * good as the packet type and remaining length was already read. Hence,
- * the probability of the remaining 2 bytes available to read is very high. */
+ * Invoking receiveConnackPacket with remainingTime as 0 would attempt to
+ * recv from network once. */
if( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK )
{
- status = receivePacket( pContext,
- *pIncomingPacket,
- remainingTimeMs );
+ status = receiveConnackPacket( pContext,
+ *pIncomingPacket );
}
+ /* TODO: Handle AUTH packets here as well. */
else
{
LogError( ( "Incorrect packet type %X received while expecting"
@@ -2505,7 +3465,10 @@ static MQTTStatus_t receiveConnack( MQTTContext_t * pContext,
pIncomingPacket->pRemainingData = pContext->networkBuffer.pBuffer;
/* Deserialize CONNACK. */
- status = MQTT_DeserializeAck( pIncomingPacket, NULL, pSessionPresent );
+ status = MQTT_DeserializeConnAck( pIncomingPacket,
+ pSessionPresent,
+ &propBuffer,
+ &pContext->connectionProperties );
}
/* If a clean session is requested, a session present should not be set by
@@ -2530,6 +3493,17 @@ static MQTTStatus_t receiveConnack( MQTTContext_t * pContext,
MQTT_Status_strerror( status ) ) );
}
+ if( ( status == MQTTSuccess ) || ( status == MQTTServerRefused ) )
+ {
+ deserializedInfo.deserializationResult = status;
+
+ if( pContext->appCallback( pContext, pIncomingPacket, &deserializedInfo,
+ NULL, &pContext->ackPropsBuffer, &propBuffer ) == false )
+ {
+ status = MQTTEventCallbackFailed;
+ }
+ }
+
return status;
}
@@ -2573,18 +3547,26 @@ static MQTTStatus_t handleUncleanSessionResumption( MQTTContext_t * pContext )
{
if( pContext->retrieveFunction( pContext, packetId, &pMqttPacket, &totalMessageLength ) != true )
{
+ LogError( ( "Failed to retrieve publish with packet ID %u", packetId ) );
status = MQTTPublishRetrieveFailed;
- break;
}
-
- MQTT_PRE_STATE_UPDATE_HOOK( pContext );
-
- if( sendBuffer( pContext, pMqttPacket, totalMessageLength ) != ( int32_t ) totalMessageLength )
+ else if( CHECK_SIZE_T_OVERFLOWS_32BIT( totalMessageLength ) ||
+ ( totalMessageLength > MQTT_MAX_PACKET_SIZE ) )
{
- status = MQTTSendFailed;
+ LogError( ( "Total packet size returned by the retrieve function exceeds the MQTT Max packet size." ) );
+ status = MQTTBadParameter;
}
+ else
+ {
+ MQTT_PRE_STATE_UPDATE_HOOK( pContext );
- MQTT_POST_STATE_UPDATE_HOOK( pContext );
+ if( sendBuffer( pContext, pMqttPacket, totalMessageLength ) != ( int32_t ) totalMessageLength )
+ {
+ status = MQTTSendFailed;
+ }
+
+ MQTT_POST_STATE_UPDATE_HOOK( pContext );
+ }
}
} while( ( packetId != MQTT_PACKET_ID_INVALID ) &&
( status == MQTTSuccess ) );
@@ -2593,6 +3575,8 @@ static MQTTStatus_t handleUncleanSessionResumption( MQTTContext_t * pContext )
return status;
}
+/*-----------------------------------------------------------*/
+
static MQTTStatus_t handleCleanSession( MQTTContext_t * pContext )
{
MQTTStatus_t status = MQTTSuccess;
@@ -2622,63 +3606,424 @@ static MQTTStatus_t handleCleanSession( MQTTContext_t * pContext )
} while( packetId != MQTT_PACKET_ID_INVALID );
}
- if( pContext->outgoingPublishRecordMaxCount > 0U )
- {
- /* Clear any existing records if a new session is established. */
- ( void ) memset( pContext->outgoingPublishRecords,
- 0x00,
- pContext->outgoingPublishRecordMaxCount * sizeof( *pContext->outgoingPublishRecords ) );
- }
+ if( pContext->outgoingPublishRecordMaxCount > 0U )
+ {
+ /* Clear any existing records if a new session is established. */
+ ( void ) memset( pContext->outgoingPublishRecords,
+ 0x00,
+ pContext->outgoingPublishRecordMaxCount * sizeof( *pContext->outgoingPublishRecords ) );
+ }
+
+ if( pContext->incomingPublishRecordMaxCount > 0U )
+ {
+ ( void ) memset( pContext->incomingPublishRecords,
+ 0x00,
+ pContext->incomingPublishRecordMaxCount * sizeof( *pContext->incomingPublishRecords ) );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validatePublishParams( const MQTTContext_t * pContext,
+ const MQTTPublishInfo_t * pPublishInfo,
+ uint16_t packetId )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ /* Validate arguments. */
+ if( ( pContext == NULL ) || ( pPublishInfo == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL: pContext=%p, "
+ "pPublishInfo=%p.",
+ ( void * ) pContext,
+ ( void * ) pPublishInfo ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
+ {
+ LogError( ( "Packet Id is 0 for PUBLISH with QoS=%u.",
+ ( unsigned int ) pPublishInfo->qos ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pPublishInfo->payloadLength > 0U ) && ( pPublishInfo->pPayload == NULL ) )
+ {
+ LogError( ( "A nonzero payload length requires a non-NULL payload: "
+ "payloadLength=%lu, pPayload=%p.",
+ ( unsigned long ) pPublishInfo->payloadLength,
+ pPublishInfo->pPayload ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) )
+ {
+ LogError( ( "Topic name length must be less than 65536." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pContext->outgoingPublishRecords == NULL ) && ( pPublishInfo->qos > MQTTQoS0 ) )
+ {
+ LogError( ( "Trying to publish a QoS > MQTTQoS0 packet when outgoing publishes "
+ "for QoS1/QoS2 have not been enabled. Please, call MQTT_InitStatefulQoS "
+ "to initialize and enable the use of QoS1/QoS2 publishes." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* MISRA else */
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateTopicFilter( const MQTTContext_t * pContext,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ size_t iterator,
+ MQTTSubscriptionType_t subscriptionType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( ( pSubscriptionList[ iterator ].pTopicFilter == NULL ) ||
+ ( pSubscriptionList[ iterator ].topicFilterLength == 0U ) )
+ {
+ LogError( ( "Invalid subscription at index %lu: Topic filter is NULL or has zero length.", iterator ) );
+ status = MQTTBadParameter;
+ }
+
+ if( ( status == MQTTSuccess ) &&
+ CHECK_SIZE_T_OVERFLOWS_16BIT( pSubscriptionList[ iterator ].topicFilterLength ) )
+ {
+ LogError( ( "Topic filter length must be less than 65536 for topic number %" PRIu32, ( uint32_t ) iterator ) );
+ status = MQTTBadParameter;
+ }
+
+ if( ( status == MQTTSuccess ) && ( subscriptionType == MQTT_TYPE_SUBSCRIBE ) )
+ {
+ if( pSubscriptionList[ iterator ].qos > MQTTQoS2 )
+ {
+ LogError( ( "Protocol Error : QoS cannot be greater than 2" ) );
+ status = MQTTBadParameter;
+ }
+ else if( checkWildcardSubscriptions( pContext->connectionProperties.isWildcardAvailable,
+ pSubscriptionList,
+ iterator ) )
+ {
+ LogError( ( "Protocol Error : Wildcard Subscriptions not allowed. " ) );
+ status = MQTTBadParameter;
+ }
+ else if( pSubscriptionList[ iterator ].retainHandlingOption > retainDoNotSendonSub )
+ {
+ LogError( ( "Protocol Error : retainHandlingOption cannot be greater than 2" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = validateSharedSubscriptions( pContext,
+ pSubscriptionList,
+ iterator );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static bool checkWildcardSubscriptions( uint8_t isWildcardAvailable,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ size_t iterator )
+{
+ bool ret = false;
+
+ if( isWildcardAvailable == 0U )
+ {
+ if( ( ( strchr( pSubscriptionList[ iterator ].pTopicFilter, ( int32_t ) '#' ) != NULL ) ||
+ ( strchr( pSubscriptionList[ iterator ].pTopicFilter, ( int32_t ) '+' ) != NULL ) ) )
+ {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateSharedSubscriptions( const MQTTContext_t * pContext,
+ const MQTTSubscribeInfo_t * pSubscriptionList,
+ const size_t iterator )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint16_t topicFilterLength = pSubscriptionList[ iterator ].topicFilterLength;
+ bool isSharedSub = ( topicFilterLength > 7U );
+ const char * shareNameEnd;
+ const char * shareNameStart;
+
+ /* Need to check this only if the length is proper. */
+ if( pSubscriptionList[ iterator ].topicFilterLength > 7U )
+ {
+ isSharedSub = ( isSharedSub ) && ( ( strncmp( pSubscriptionList[ iterator ].pTopicFilter, "$share/", 7U ) ) == 0 );
+ }
+
+ if( isSharedSub )
+ {
+ shareNameStart = &( pSubscriptionList[ iterator ].pTopicFilter[ 7U ] );
+ shareNameEnd = memchr( shareNameStart, ( int32_t ) '/', ( size_t ) topicFilterLength - 7U );
+
+ if( ( shareNameEnd == NULL ) ||
+ ( shareNameEnd == &( pSubscriptionList[ iterator ].pTopicFilter[ 7 ] ) ) )
+ {
+ LogError( ( "Protocol Error : ShareName is not present , missing or empty" ) );
+ status = MQTTBadParameter;
+ }
+ else if( pSubscriptionList[ iterator ].noLocalOption )
+ {
+ LogError( ( "Protocol Error : noLocalOption cannot be 1 for shared subscriptions" ) );
+ status = MQTTBadParameter;
+ }
+ else if( pContext->connectionProperties.isSharedAvailable == 0U )
+ {
+ LogError( ( "Protocol Error : Shared Subscriptions not allowed" ) );
+ status = MQTTBadParameter;
+ }
+ else if( shareNameEnd == &( pSubscriptionList[ iterator ].pTopicFilter[ topicFilterLength - 1U ] ) )
+ {
+ LogError( ( "Protocol Error : Topic filter after share name is missing" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ const char * ptr;
+
+ for( ptr = shareNameStart; ptr < shareNameEnd; ptr++ )
+ {
+ if( ( *ptr == '#' ) || ( *ptr == '+' ) )
+ {
+ status = MQTTBadParameter;
+ break; /* Invalid share name */
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static void addSubscriptionOptions( const MQTTSubscribeInfo_t subscriptionInfo,
+ uint8_t * pSubscriptionOptionsArray,
+ size_t currentOptionIndex )
+{
+ uint8_t subscriptionOptions = 0U;
+
+ if( subscriptionInfo.qos == MQTTQoS1 )
+ {
+ LogInfo( ( "Adding QoS as QoS 1 in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_QOS1 );
+ }
+ else if( subscriptionInfo.qos == MQTTQoS2 )
+ {
+ LogInfo( ( "Adding QoS as QoS 2 in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_QOS2 );
+ }
+ else
+ {
+ LogInfo( ( "Adding QoS as QoS 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( subscriptionInfo.noLocalOption )
+ {
+ LogInfo( ( "Adding noLocalOption in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_NO_LOCAL );
+ }
+ else
+ {
+ LogDebug( ( "Adding noLocalOption as 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( subscriptionInfo.retainAsPublishedOption )
+ {
+ LogInfo( ( " retainAsPublishedOption in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_AS_PUBLISHED );
+ }
+ else
+ {
+ LogDebug( ( "retainAsPublishedOption as 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( subscriptionInfo.retainHandlingOption == retainSendOnSub )
+ {
+ LogInfo( ( "Send Retain messages at the time of subscribe" ) );
+ }
+ else if( subscriptionInfo.retainHandlingOption == retainSendOnSubIfNotPresent )
+ {
+ LogInfo( ( "Send retained messages at subscribe only if the subscription does not currently exist" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_HANDLING1 );
+ }
+ else
+ {
+ LogInfo( ( "Do not send retained messages at subscribe" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_HANDLING2 );
+ }
+
+ pSubscriptionOptionsArray[ currentOptionIndex ] = subscriptionOptions;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t handleSubUnsubAck( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint16_t packetIdentifier;
+ MQTTEventCallback_t appCallback;
+ MQTTDeserializedInfo_t deserializedInfo;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ MQTTReasonCodeInfo_t ackInfo = { 0 };
+
+ assert( pContext != NULL );
+ assert( pIncomingPacket != NULL );
+ assert( pContext->appCallback != NULL );
+
+ appCallback = pContext->appCallback;
+
+ status = MQTT_DeserializeAck( pIncomingPacket,
+ &packetIdentifier,
+ &ackInfo,
+ &propBuffer,
+ &pContext->connectionProperties );
- if( pContext->incomingPublishRecordMaxCount > 0U )
+ LogInfo( ( "Ack packet deserialized with result: %s.",
+ MQTT_Status_strerror( status ) ) );
+
+ if( ( status == MQTTSuccess ) || ( status == MQTTServerRefused ) )
{
- ( void ) memset( pContext->incomingPublishRecords,
- 0x00,
- pContext->incomingPublishRecordMaxCount * sizeof( *pContext->incomingPublishRecords ) );
+ deserializedInfo.packetIdentifier = packetIdentifier;
+ deserializedInfo.deserializationResult = status;
+ deserializedInfo.pPublishInfo = NULL;
+ deserializedInfo.pReasonCode = &ackInfo;
+
+ /* Invoke application callback to hand the buffer over to application */
+ if( appCallback( pContext, pIncomingPacket, &deserializedInfo, NULL,
+ &pContext->ackPropsBuffer, &propBuffer ) == false )
+ {
+ status = MQTTEventCallbackFailed;
+ }
}
return status;
}
-static MQTTStatus_t validatePublishParams( const MQTTContext_t * pContext,
- const MQTTPublishInfo_t * pPublishInfo,
- uint16_t packetId )
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t sendDisconnectWithoutCopy( MQTTContext_t * pContext,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
+ int32_t bytesSentOrError;
+ size_t ioVectorLength = 0U;
+ uint32_t totalMessageLength = 0U;
+ size_t disconnectPropLen = 0U;
MQTTStatus_t status = MQTTSuccess;
- /* Validate arguments. */
- if( ( pContext == NULL ) || ( pPublishInfo == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pContext=%p, "
- "pPublishInfo=%p.",
- ( void * ) pContext,
- ( void * ) pPublishInfo ) );
- status = MQTTBadParameter;
- }
- else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
+ /* Maximum number of bytes required by the fixed size part of the CONNECT
+ * packet header according to the MQTT specification.
+ * MQTT Control Byte 0 + 1 = 1
+ * Remaining length (max) + 4 = 5
+ * Reason Code + 1 = 6
+ *
+ * Note that the reason code is not actually 'fixed'. But it avoids much
+ * calculation and potential TCP/TLS overhead in some implementations later
+ * at the cost of one byte on the stack.
+ */
+ uint8_t fixedHeader[ 6U ];
+
+ /**
+ * Maximum number of bytes to send the Property Length.
+ * Property Length 0 + 4 = 4
+ */
+ uint8_t propertyLength[ 4U ];
+
+ /* The maximum vectors required to encode and send a disconnect packet. The
+ * breakdown is shown below.
+ * disconnect Header 0 + 1 = 1
+ * Property Length + 1 = 2
+ * Optional Properties + 1 = 3
+ * */
+ TransportOutVector_t pIoVector[ 3U ];
+
+ uint8_t * pIndex = fixedHeader;
+ TransportOutVector_t * iterator = pIoVector;
+
+ assert( pContext != NULL );
+ assert( remainingLength < MQTT_REMAINING_LENGTH_INVALID );
+
+ if( pPropertyBuilder != NULL )
{
- LogError( ( "Packet Id is 0 for PUBLISH with QoS=%u.",
- ( unsigned int ) pPublishInfo->qos ) );
- status = MQTTBadParameter;
+ assert( pReasonCode != NULL );
}
- else if( ( pPublishInfo->payloadLength > 0U ) && ( pPublishInfo->pPayload == NULL ) )
+
+ /* Only for fixed size fields. */
+ pIndex = serializeDisconnectFixed( pIndex, pReasonCode, remainingLength );
+ iterator->iov_base = fixedHeader;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - fixedHeader );
+ assert( iterator->iov_len <= 6U );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
{
- LogError( ( "A nonzero payload length requires a non-NULL payload: "
- "payloadLength=%lu, pPayload=%p.",
- ( unsigned long ) pPublishInfo->payloadLength,
- pPublishInfo->pPayload ) );
- status = MQTTBadParameter;
+ disconnectPropLen = pPropertyBuilder->currentIndex;
}
- else if( ( pContext->outgoingPublishRecords == NULL ) && ( pPublishInfo->qos > MQTTQoS0 ) )
+
+ pIndex = encodeVariableLength( propertyLength, disconnectPropLen );
+ iterator->iov_base = propertyLength;
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-182 */
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_18_2_violation] */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ iterator->iov_len = ( size_t ) ( pIndex - propertyLength );
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+
+ if( disconnectPropLen > 0U )
{
- LogError( ( "Trying to publish a QoS > MQTTQoS0 packet when outgoing publishes "
- "for QoS1/QoS2 have not been enabled. Please, call MQTT_InitStatefulQoS "
- "to initialize and enable the use of QoS1/QoS2 publishes." ) );
- status = MQTTBadParameter;
+ iterator->iov_base = pPropertyBuilder->pBuffer;
+ iterator->iov_len = pPropertyBuilder->currentIndex;
+
+ if( ADDITION_WILL_OVERFLOW_U32( totalMessageLength, pPropertyBuilder->currentIndex ) ||
+ ( ( totalMessageLength + pPropertyBuilder->currentIndex ) > MQTT_MAX_PACKET_SIZE ) )
+ {
+ LogError( ( "Total MQTT packet size must be less than 268435461" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ totalMessageLength += iterator->iov_len;
+ iterator++;
+ ioVectorLength++;
+ }
}
- else
+
+ if( status == MQTTSuccess )
{
- /* MISRA else */
+ bytesSentOrError = sendMessageVector( pContext, pIoVector, ioVectorLength );
+
+ if( bytesSentOrError != ( int32_t ) totalMessageLength )
+ {
+ status = MQTTSendFailed;
+ LogError( ( "Failed to send disconnect packet." ) );
+ }
}
return status;
@@ -2735,9 +4080,13 @@ MQTTStatus_t MQTT_Init( MQTTContext_t * pContext,
pContext->getTime = getTimeFunction;
pContext->appCallback = userCallback;
pContext->networkBuffer = *pNetworkBuffer;
+ pContext->ackPropsBuffer.pBuffer = NULL;
/* Zero is not a valid packet ID per MQTT spec. Start from 1. */
pContext->nextPacketId = 1;
+
+ /* Setting default connect properties in our application */
+ status = MQTT_InitConnect( &( pContext->connectionProperties ) );
}
return status;
@@ -2749,7 +4098,9 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext,
MQTTPubAckInfo_t * pOutgoingPublishRecords,
size_t outgoingPublishCount,
MQTTPubAckInfo_t * pIncomingPublishRecords,
- size_t incomingPublishCount )
+ size_t incomingPublishCount,
+ uint8_t * pAckPropsBuf,
+ size_t ackPropsBufLength )
{
MQTTStatus_t status = MQTTSuccess;
@@ -2795,6 +4146,16 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext,
pContext->incomingPublishRecords = pIncomingPublishRecords;
pContext->outgoingPublishRecordMaxCount = outgoingPublishCount;
pContext->outgoingPublishRecords = pOutgoingPublishRecords;
+
+ if( ( pAckPropsBuf != NULL ) && ( ackPropsBufLength != 0U ) )
+ {
+ status = MQTTPropertyBuilder_Init( &pContext->ackPropsBuffer, pAckPropsBuf, ackPropsBufLength );
+ }
+ else
+ {
+ pContext->ackPropsBuffer.pBuffer = NULL;
+ pContext->ackPropsBuffer.bufferLength = 0;
+ }
}
return status;
@@ -2854,7 +4215,7 @@ MQTTStatus_t MQTT_CancelCallback( const MQTTContext_t * pContext,
}
else if( pContext->outgoingPublishRecords == NULL )
{
- LogError( ( "QoS1/QoS2 is not initialized for use. Please, "
+ LogError( ( "QoS1/QoS2 is not initialized for use. Please "
"call MQTT_InitStatefulQoS to enable QoS1 and QoS2 "
"publishes.\n" ) );
status = MQTTBadParameter;
@@ -2919,14 +4280,17 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
uint32_t timeoutMs,
- bool * pSessionPresent )
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTPropBuilder_t * pWillPropertyBuilder )
{
- size_t remainingLength = 0UL, packetSize = 0UL;
+ uint32_t remainingLength = 0UL, packetSize = 0UL;
MQTTStatus_t status = MQTTSuccess;
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTConnectionStatus_t connectStatus;
-
- incomingPacket.type = ( uint8_t ) 0;
+ uint8_t backupPropBuffer[ 5 ];
+ MQTTPropBuilder_t backupPropBuilder = { 0 };
+ MQTTPropBuilder_t * pBackupPropBuilder = pPropertyBuilder;
if( ( pContext == NULL ) || ( pConnectInfo == NULL ) || ( pSessionPresent == NULL ) )
{
@@ -2938,11 +4302,61 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
status = MQTTBadParameter;
}
+ if( ( status == MQTTSuccess ) && ( pWillInfo != NULL ) && ( pWillPropertyBuilder != NULL ) )
+ {
+ status = MQTT_ValidateWillProperties( pWillPropertyBuilder );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( pBackupPropBuilder != NULL )
+ {
+ bool isRequestProblemInfoSet;
+ uint32_t packetMaxSize = UINT32_MAX;
+ status = MQTT_ValidateConnectProperties( pBackupPropBuilder,
+ &isRequestProblemInfoSet,
+ &packetMaxSize );
+
+ /* Update the field in the context so that it can be gated on. */
+ pContext->connectionProperties.requestProblemInfo = isRequestProblemInfoSet;
+
+ if( packetMaxSize > pContext->networkBuffer.size )
+ {
+ LogError( ( "Properties have packet maximum set to %" PRIu32
+ " whereas the buffer length is %" PRIu32
+ ". Please make sure that buffer is at least as big as %" PRIu32
+ " otherwise the server can send a bigger packet which cannot be processed by the coreMQTT library.",
+ packetMaxSize,
+ ( uint32_t ) pContext->networkBuffer.size,
+ packetMaxSize ) );
+ status = MQTTBadParameter;
+ }
+ }
+ else
+ {
+ pBackupPropBuilder = &backupPropBuilder;
+
+ backupPropBuilder.pBuffer = backupPropBuffer;
+ backupPropBuilder.bufferLength = sizeof( backupPropBuffer );
+
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pContext->networkBuffer.size ) );
+
+ LogInfo( ( "Application has not set any properties. Adding a property to set the maximum "
+ "packet size received from the server for the client to be %" PRIu32 ".",
+ ( uint32_t ) pContext->networkBuffer.size ) );
+ status = MQTTPropAdd_MaxPacketSize( pBackupPropBuilder,
+ pContext->networkBuffer.size,
+ NULL );
+ }
+ }
+
if( status == MQTTSuccess )
{
/* Get MQTT connect packet size and remaining length. */
status = MQTT_GetConnectPacketSize( pConnectInfo,
pWillInfo,
+ pBackupPropBuilder,
+ pWillPropertyBuilder,
&remainingLength,
&packetSize );
/* coverity[sensitive_data_leak] */
@@ -2967,9 +4381,14 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
status = sendConnectWithoutCopy( pContext,
pConnectInfo,
pWillInfo,
- remainingLength );
+ remainingLength,
+ pBackupPropBuilder,
+ pWillPropertyBuilder );
}
+ /* TODO: As part of CONNECT/CONNACK setup, there can be AUTH packets sent.
+ * It is not dealt with currently. */
+
/* Read CONNACK from transport layer. */
if( status == MQTTSuccess )
{
@@ -2980,6 +4399,29 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
pSessionPresent );
}
+ /**
+ * Update the maximum number of concurrent incoming and outgoing PUBLISH records
+ * based on MQTT 5.0 Receive Maximum property :
+ *
+ * - For incoming publishes: Use the minimum between the client's configured receive maximum
+ * (In the MQTT_Init function) and the receive maximum value sent in CONNECT properties
+ *
+ * - For outgoing publishes: Use the minimum between the client's configured maximum
+ * (In the MQTT_Init function) and the server's receive maximum value received in CONNACK properties
+ **/
+ if( status == MQTTSuccess )
+ {
+ if( pContext->connectionProperties.receiveMax < pContext->incomingPublishRecordMaxCount )
+ {
+ pContext->incomingPublishRecordMaxCount = pContext->connectionProperties.receiveMax;
+ }
+
+ if( pContext->connectionProperties.serverReceiveMax < pContext->outgoingPublishRecordMaxCount )
+ {
+ pContext->outgoingPublishRecordMaxCount = pContext->connectionProperties.serverReceiveMax;
+ }
+ }
+
if( ( status == MQTTSuccess ) && ( *pSessionPresent != true ) )
{
status = handleCleanSession( pContext );
@@ -2988,8 +4430,14 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
if( status == MQTTSuccess )
{
pContext->connectStatus = MQTTConnected;
- /* Initialize keep-alive fields after a successful connection. */
- pContext->keepAliveIntervalSec = pConnectInfo->keepAliveSeconds;
+
+ /**
+ * Initialize the client's keep-alive timer using the Server Keep Alive value
+ * received in the CONNACK.
+ * This value overrides the client's original keep-alive setting,
+ * as per MQTT v5 specification.
+ */
+ pContext->keepAliveIntervalSec = pContext->connectionProperties.serverKeepAlive;
pContext->waitingForPingResp = false;
pContext->pingReqSendTimeMs = 0U;
}
@@ -3046,24 +4494,36 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId )
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTConnectionStatus_t connectStatus;
- size_t remainingLength = 0UL, packetSize = 0UL;
+ uint32_t remainingLength = 0UL;
+ uint32_t packetSize = 0UL;
+ MQTTStatus_t status = MQTTSuccess;
- /* Validate arguments. */
- MQTTStatus_t status = validateSubscribeUnsubscribeParams( pContext,
- pSubscriptionList,
- subscriptionCount,
- packetId );
+ status = validateSubscribeUnsubscribeParams( pContext,
+ pSubscriptionList,
+ subscriptionCount,
+ packetId,
+ MQTT_TYPE_SUBSCRIBE );
+
+ if( ( status == MQTTSuccess ) && ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ bool isSubscriptionIdAvailable = pContext->connectionProperties.isSubscriptionIdAvailable;
+ status = MQTT_ValidateSubscribeProperties( isSubscriptionIdAvailable,
+ pPropertyBuilder );
+ }
if( status == MQTTSuccess )
{
- /* Get the remaining length and packet size.*/
+ /* Get the remaining length and packet size. */
status = MQTT_GetSubscribePacketSize( pSubscriptionList,
subscriptionCount,
+ pPropertyBuilder,
&remainingLength,
- &packetSize );
+ &packetSize,
+ pContext->connectionProperties.serverMaxPacketSize );
LogDebug( ( "SUBSCRIBE packet size is %lu and remaining length is %lu.",
( unsigned long ) packetSize,
( unsigned long ) remainingLength ) );
@@ -3087,7 +4547,8 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
pSubscriptionList,
subscriptionCount,
packetId,
- remainingLength );
+ remainingLength,
+ pPropertyBuilder );
}
MQTT_POST_STATE_UPDATE_HOOK( pContext );
@@ -3100,13 +4561,15 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
const MQTTPublishInfo_t * pPublishInfo,
- uint16_t packetId )
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
size_t headerSize = 0UL;
- size_t remainingLength = 0UL;
- size_t packetSize = 0UL;
+ uint32_t remainingLength = 0UL;
+ uint32_t packetSize = 0UL;
MQTTPublishState_t publishStatus = MQTTStateNull;
MQTTConnectionStatus_t connectStatus;
+ uint16_t topicAlias = 0U;
/* Maximum number of bytes required by the 'fixed' part of the PUBLISH
* packet header according to the MQTT specifications.
@@ -3120,16 +4583,36 @@ MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
* an extra call to 'send' (in case writev is not defined) to send the
* topic length. */
uint8_t mqttHeader[ 7U ];
+ MQTTStatus_t status = MQTTSuccess;
/* Validate arguments. */
- MQTTStatus_t status = validatePublishParams( pContext, pPublishInfo, packetId );
+ status = validatePublishParams( pContext, pPublishInfo, packetId );
+
+ /* Validate Publish Properties and extract Topic Alias from the properties. */
+ if( ( status == MQTTSuccess ) && ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ status = MQTT_ValidatePublishProperties( pContext->connectionProperties.serverTopicAliasMax,
+ pPropertyBuilder, &topicAlias );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Validate Publish Properties with the persistent Connection Properties. */
+ status = MQTT_ValidatePublishParams( pPublishInfo,
+ pContext->connectionProperties.retainAvailable,
+ pContext->connectionProperties.serverMaxQos,
+ topicAlias,
+ pContext->connectionProperties.serverMaxPacketSize );
+ }
if( status == MQTTSuccess )
{
- /* Get the remaining length and packet size.*/
+ /* Get the remaining length and packet size. */
status = MQTT_GetPublishPacketSize( pPublishInfo,
+ pPropertyBuilder,
&remainingLength,
- &packetSize );
+ &packetSize,
+ pContext->connectionProperties.serverMaxPacketSize );
}
if( status == MQTTSuccess )
@@ -3142,6 +4625,8 @@ MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
if( status == MQTTSuccess )
{
+ assert( headerSize <= 7U );
+
/* Take the mutex as multiple send calls are required for sending this
* packet. */
MQTT_PRE_STATE_UPDATE_HOOK( pContext );
@@ -3176,7 +4661,8 @@ MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
pPublishInfo,
mqttHeader,
headerSize,
- packetId );
+ packetId,
+ pPropertyBuilder );
}
if( ( status == MQTTSuccess ) &&
@@ -3223,7 +4709,7 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext )
{
int32_t sendResult = 0;
MQTTStatus_t status = MQTTSuccess;
- size_t packetSize = 0U;
+ uint32_t packetSize = 0U;
/* MQTT ping packets are of fixed length. */
uint8_t pingreqPacket[ 2U ];
MQTTFixedBuffer_t localBuffer;
@@ -3311,27 +4797,38 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext )
MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId )
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTConnectionStatus_t connectStatus;
- size_t remainingLength = 0UL, packetSize = 0UL;
+ uint32_t remainingLength = 0UL;
+ uint32_t packetSize = 0UL;
+ MQTTStatus_t status = MQTTSuccess;
/* Validate arguments. */
- MQTTStatus_t status = validateSubscribeUnsubscribeParams( pContext,
- pSubscriptionList,
- subscriptionCount,
- packetId );
+ status = validateSubscribeUnsubscribeParams( pContext,
+ pSubscriptionList,
+ subscriptionCount,
+ packetId,
+ MQTT_TYPE_UNSUBSCRIBE );
+
+ if( ( status == MQTTSuccess ) && ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ status = MQTT_ValidateUnsubscribeProperties( pPropertyBuilder );
+ }
if( status == MQTTSuccess )
{
- /* Get the remaining length and packet size.*/
+ /* Get the remaining length and packet size. */
status = MQTT_GetUnsubscribePacketSize( pSubscriptionList,
subscriptionCount,
+ pPropertyBuilder,
&remainingLength,
- &packetSize );
- LogDebug( ( "UNSUBSCRIBE packet size is %lu and remaining length is %lu.",
- ( unsigned long ) packetSize,
- ( unsigned long ) remainingLength ) );
+ &packetSize,
+ pContext->connectionProperties.serverMaxPacketSize );
+ LogInfo( ( "UNSUBSCRIBE packet size is %lu and remaining length is %lu.",
+ ( unsigned long ) packetSize,
+ ( unsigned long ) remainingLength ) );
}
if( status == MQTTSuccess )
@@ -3352,7 +4849,8 @@ MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext,
pSubscriptionList,
subscriptionCount,
packetId,
- remainingLength );
+ remainingLength,
+ pPropertyBuilder );
}
MQTT_POST_STATE_UPDATE_HOOK( pContext );
@@ -3363,37 +4861,43 @@ MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_Disconnect( MQTTContext_t * pContext )
+MQTTStatus_t MQTT_Disconnect( MQTTContext_t * pContext,
+ const MQTTPropBuilder_t * pPropertyBuilder,
+ MQTTSuccessFailReasonCode_t * pReasonCode )
{
- size_t packetSize = 0U;
- int32_t sendResult = 0;
+ uint32_t packetSize = 0U;
+ uint32_t remainingLength = 0U;
MQTTStatus_t status = MQTTSuccess;
- MQTTFixedBuffer_t localBuffer;
- uint8_t disconnectPacket[ 2U ];
MQTTConnectionStatus_t connectStatus;
- localBuffer.pBuffer = disconnectPacket;
- localBuffer.size = 2U;
-
/* Validate arguments. */
if( pContext == NULL )
{
LogError( ( "pContext cannot be NULL." ) );
status = MQTTBadParameter;
}
+ else if( ( pReasonCode == NULL ) && ( pPropertyBuilder != NULL ) )
+ {
+ LogError( ( "Reason code must be provided if the properties are non-NULL." ) );
+ status = MQTTBadParameter;
+ }
- if( status == MQTTSuccess )
+ if( ( status == MQTTSuccess ) && ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
{
- /* Get MQTT DISCONNECT packet size. */
- status = MQTT_GetDisconnectPacketSize( &packetSize );
- LogDebug( ( "MQTT DISCONNECT packet size is %lu.",
- ( unsigned long ) packetSize ) );
+ status = MQTT_ValidateDisconnectProperties( pContext->connectionProperties.sessionExpiry,
+ pPropertyBuilder );
}
if( status == MQTTSuccess )
{
- /* Serialize MQTT DISCONNECT packet. */
- status = MQTT_SerializeDisconnect( &localBuffer );
+ /* Get MQTT DISCONNECT packet size. */
+ status = MQTT_GetDisconnectPacketSize( pPropertyBuilder,
+ &remainingLength,
+ &packetSize,
+ pContext->connectionProperties.serverMaxPacketSize,
+ pReasonCode );
+ LogDebug( ( "MQTT DISCONNECT packet size is %lu.",
+ ( unsigned long ) packetSize ) );
}
if( status == MQTTSuccess )
@@ -3417,25 +4921,10 @@ MQTTStatus_t MQTT_Disconnect( MQTTContext_t * pContext )
pContext->index = 0;
( void ) memset( pContext->networkBuffer.pBuffer, 0, pContext->networkBuffer.size );
- LogError( ( "MQTT Connection Disconnected Successfully" ) );
-
- /* Here we do not use vectors as the disconnect packet has fixed fields
- * which do not reside in user provided buffers. Thus, it can be sent
- * using a simple send call. */
- sendResult = sendBuffer( pContext,
- localBuffer.pBuffer,
- packetSize );
+ LogInfo( ( "MQTT Connection Disconnected Successfully" ) );
- if( sendResult < ( int32_t ) packetSize )
- {
- LogError( ( "Transport send failed for DISCONNECT packet." ) );
- status = MQTTSendFailed;
- }
- else
- {
- LogDebug( ( "Sent %ld bytes of DISCONNECT packet.",
- ( long int ) sendResult ) );
- }
+ status = sendDisconnectWithoutCopy( pContext, pReasonCode,
+ remainingLength, pPropertyBuilder );
}
MQTT_POST_STATE_UPDATE_HOOK( pContext );
@@ -3529,9 +5018,9 @@ uint16_t MQTT_GetPacketId( MQTTContext_t * pContext )
/*-----------------------------------------------------------*/
MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
- const uint16_t topicNameLength,
+ const size_t topicNameLength,
const char * pTopicFilter,
- const uint16_t topicFilterLength,
+ const size_t topicFilterLength,
bool * pIsMatch )
{
MQTTStatus_t status = MQTTSuccess;
@@ -3560,6 +5049,16 @@ MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
LogError( ( "Invalid paramater: Output parameter, pIsMatch, is NULL" ) );
status = MQTTBadParameter;
}
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( topicNameLength ) )
+ {
+ LogError( ( "topicNameLength must be fit in a 16-bit value (<65535)" ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( topicFilterLength ) )
+ {
+ LogError( ( "topicFilterLength must be fit in a 16-bit value (<65535)" ) );
+ status = MQTTBadParameter;
+ }
else
{
/* Check for an exact match if the incoming topic name and the registered
@@ -3572,13 +5071,13 @@ MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
if( matchStatus == false )
{
/* If an exact match was not found, match against wildcard characters in
- * topic filter.*/
+ * topic filter. */
/* Determine if topic filter starts with a wildcard. */
topicFilterStartsWithWildcard = ( pTopicFilter[ 0 ] == '+' ) ||
( pTopicFilter[ 0 ] == '#' );
- /* Note: According to the MQTT 3.1.1 specification, incoming PUBLISH topic names
+ /* Note: According to the MQTT 5.0 specification, incoming PUBLISH topic names
* starting with "$" character cannot be matched against topic filter starting with
* a wildcard, i.e. for example, "$SYS/sport" cannot be matched with "#" or
* "+/sport" topic filters. */
@@ -3602,6 +5101,7 @@ MQTTStatus_t MQTT_GetSubAckStatusCodes( const MQTTPacketInfo_t * pSubackPacket,
size_t * pPayloadSize )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0;
if( pSubackPacket == NULL )
{
@@ -3632,23 +5132,44 @@ MQTTStatus_t MQTT_GetSubAckStatusCodes( const MQTTPacketInfo_t * pSubackPacket,
status = MQTTBadParameter;
}
- /* A SUBACK must have a remaining length of at least 3 to accommodate the
- * packet identifier and at least 1 return code. */
- else if( pSubackPacket->remainingLength < 3U )
+ /* A SUBACK must have a remaining length of at least 4 to accommodate the
+ * packet identifier, atleast 1 byte for the property length and at least 1 return code. */
+ else if( pSubackPacket->remainingLength < 4U )
{
LogError( ( "Invalid parameter: Packet remaining length is invalid: "
- "Should be greater than 2 for SUBACK packet: InputRemainingLength=%lu",
+ "Should be greater than or equal to 4 for SUBACK packet: InputRemainingLength=%lu",
( unsigned long ) pSubackPacket->remainingLength ) );
status = MQTTBadParameter;
}
+ else if( pSubackPacket->remainingLength >= MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "Remaining length cannot be larger than MQTT maximum (268435456)." ) );
+ status = MQTTBadParameter;
+ }
else
{
- /* According to the MQTT 3.1.1 protocol specification, the "Remaining Length" field is a
- * length of the variable header (2 bytes) plus the length of the payload.
- * Therefore, we add 2 positions for the starting address of the payload, and
- * subtract 2 bytes from the remaining length for the length of the payload.*/
- *pPayloadStart = &pSubackPacket->pRemainingData[ sizeof( uint16_t ) ];
- *pPayloadSize = pSubackPacket->remainingLength - sizeof( uint16_t );
+ /* According to the MQTT 5.0 specification, the "Remaining Length" field represents the
+ * combined length of the variable header and the payload. In a SUBACK packet, the variable
+ * header consists of the Packet Identifier (2 bytes) followed by the properties.
+ *
+ * To locate the start of the payload:
+ * - Skip the 2-byte Packet Identifier.
+ * - Then skip the properties, whose total length is decoded using the
+ * decodeSubackPropertyLength() function.
+ *
+ * The payload starts immediately after the properties.
+ * Its size is calculated by subtracting the size of the variable header
+ * (2 bytes for Packet ID + property length) from the remaining length.
+ */
+ status = decodeSubackPropertyLength( &pSubackPacket->pRemainingData[ sizeof( uint16_t ) ],
+ pSubackPacket->remainingLength,
+ &propertyLength );
+
+ if( status == MQTTSuccess )
+ {
+ *pPayloadStart = &pSubackPacket->pRemainingData[ sizeof( uint16_t ) + propertyLength ];
+ *pPayloadSize = pSubackPacket->remainingLength - sizeof( uint16_t ) - propertyLength;
+ }
}
return status;
@@ -3740,19 +5261,38 @@ const char * MQTT_Status_strerror( MQTTStatus_t status )
/*-----------------------------------------------------------*/
-size_t MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec )
+MQTTStatus_t MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec,
+ size_t * pOutput )
{
size_t memoryRequired = 0;
size_t i;
const TransportOutVector_t * pTransportVec = pVec->pVector;
- size_t vecLen = pVec->vectorLen;
+ size_t vecLen;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( pVec != NULL );
+ assert( pOutput != NULL );
+
+ vecLen = pVec->vectorLen;
for( i = 0; i < vecLen; i++ )
{
+ if( ADDITION_WILL_OVERFLOW_SIZE_T( memoryRequired, pTransportVec[ i ].iov_len ) )
+ {
+ LogError( ( "Adding all the vectors together will overflow size_t bounds!" ) );
+ status = MQTTBadParameter;
+ break;
+ }
+
memoryRequired += pTransportVec[ i ].iov_len;
}
- return memoryRequired;
+ if( status == MQTTSuccess )
+ {
+ *pOutput = memoryRequired;
+ }
+
+ return status;
}
/*-----------------------------------------------------------*/
@@ -3760,11 +5300,17 @@ size_t MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec )
void MQTT_SerializeMQTTVec( uint8_t * pAllocatedMem,
const MQTTVec_t * pVec )
{
- const TransportOutVector_t * pTransportVec = pVec->pVector;
- const size_t vecLen = pVec->vectorLen;
+ TransportOutVector_t * pTransportVec;
+ size_t vecLen;
size_t index = 0;
size_t i = 0;
+ assert( pAllocatedMem != NULL );
+ assert( pVec != NULL );
+
+ pTransportVec = pVec->pVector;
+ vecLen = pVec->vectorLen;
+
for( i = 0; i < vecLen; i++ )
{
( void ) memcpy( ( void * ) &pAllocatedMem[ index ], ( const void * ) pTransportVec[ i ].iov_base, pTransportVec[ i ].iov_len );
@@ -3773,3 +5319,80 @@ void MQTT_SerializeMQTTVec( uint8_t * pAllocatedMem,
}
/*-----------------------------------------------------------*/
+
+const char * MQTT_GetPacketTypeString( uint8_t packetType )
+{
+ char * retVal;
+
+ if( ( packetType & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH )
+ {
+ retVal = "PUBLISH";
+ }
+ else
+ {
+ switch( packetType )
+ {
+ case MQTT_PACKET_TYPE_CONNECT:
+ retVal = "CONNECT";
+ break;
+
+ case MQTT_PACKET_TYPE_CONNACK:
+ retVal = "CONNACK";
+ break;
+
+ case MQTT_PACKET_TYPE_PUBACK:
+ retVal = "PUBACK";
+ break;
+
+ case MQTT_PACKET_TYPE_PUBREC:
+ retVal = "PUBREC";
+ break;
+
+ case MQTT_PACKET_TYPE_PUBREL:
+ retVal = "PUBREL";
+ break;
+
+ case MQTT_PACKET_TYPE_PUBCOMP:
+ retVal = "PUBCOMP";
+ break;
+
+ case MQTT_PACKET_TYPE_SUBSCRIBE:
+ retVal = "SUBSCRIBE";
+ break;
+
+ case MQTT_PACKET_TYPE_SUBACK:
+ retVal = "SUBACK";
+ break;
+
+ case MQTT_PACKET_TYPE_UNSUBSCRIBE:
+ retVal = "UNSUBSCRIBE";
+ break;
+
+ case MQTT_PACKET_TYPE_UNSUBACK:
+ retVal = "UNSUBACK";
+ break;
+
+ case MQTT_PACKET_TYPE_PINGREQ:
+ retVal = "PINGREQ";
+ break;
+
+ case MQTT_PACKET_TYPE_PINGRESP:
+ retVal = "PINGRESP";
+ break;
+
+ case MQTT_PACKET_TYPE_DISCONNECT:
+ retVal = "DISCONNECT";
+ break;
+
+ case MQTT_PACKET_TYPE_AUTH:
+ retVal = "AUTH";
+ break;
+
+ default:
+ retVal = "UNKNOWN";
+ break;
+ }
+ }
+
+ return retVal;
+}
diff --git a/source/core_mqtt_prop_deserializer.c b/source/core_mqtt_prop_deserializer.c
new file mode 100644
index 000000000..6ed693091
--- /dev/null
+++ b/source/core_mqtt_prop_deserializer.c
@@ -0,0 +1,848 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_prop_deserializer.c
+ * @brief Implements the user-facing functions to de-serialize user-properties.
+ */
+#include
+#include
+#include
+
+#include "core_mqtt_serializer.h"
+
+#include "private/core_mqtt_serializer_private.h"
+
+/* Include config defaults header to get default values of configs. */
+#include "core_mqtt_config_defaults.h"
+
+/**
+ * @brief Checks the parameters to all the internal/external 'get' property
+ * functions.
+ *
+ * @param[in] mqttPropBuilder The property builder struct.
+ * @param[in] currentIndex The index of the property in the buffer.
+ *
+ * @return MQTTSuccess if all the checks pass;
+ */
+static inline MQTTStatus_t checkPropBuilderParams( MQTTPropBuilder_t * mqttPropBuilder,
+ size_t * currentIndex );
+
+/**
+ * @brief Get a uint8 property value from the property builder.
+ *
+ * This function extracts a uint8 property value from the property builder
+ * at the specified index and validates that it matches the expected property ID.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * Updated to point past the property on success.
+ * @param[in] propertyId Expected property ID to validate against.
+ * @param[out] property Pointer to store the extracted uint8 property value.
+ *
+ * @return #MQTTSuccess if the property is successfully extracted;
+ * #MQTTBadParameter if parameters are invalid or property ID doesn't match.
+ */
+static MQTTStatus_t getPropUint8( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint8_t * property );
+
+/**
+ * @brief Get a uint16 property value from the property builder.
+ *
+ * This function extracts a uint16 property value from the property builder
+ * at the specified index and validates that it matches the expected property ID.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * Updated to point past the property on success.
+ * @param[in] propertyId Expected property ID to validate against.
+ * @param[out] property Pointer to store the extracted uint16 property value.
+ *
+ * @return #MQTTSuccess if the property is successfully extracted;
+ * #MQTTBadParameter if parameters are invalid or property ID doesn't match.
+ */
+static MQTTStatus_t getPropUint16( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint16_t * property );
+
+/**
+ * @brief Get a uint32 property value from the property builder.
+ *
+ * This function extracts a uint32 property value from the property builder
+ * at the specified index and validates that it matches the expected property ID.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * Updated to point past the property on success.
+ * @param[in] propertyId Expected property ID to validate against.
+ * @param[out] property Pointer to store the extracted uint32 property value.
+ *
+ * @return #MQTTSuccess if the property is successfully extracted;
+ * #MQTTBadParameter if parameters are invalid or property ID doesn't match.
+ */
+static MQTTStatus_t getPropUint32( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint32_t * property );
+
+/**
+ * @brief Get a UTF-8 string property value from the property builder.
+ *
+ * This function extracts a UTF-8 string property value from the property builder
+ * at the specified index and validates that it matches the expected property ID.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * Updated to point past the property on success.
+ * @param[in] propertyId Expected property ID to validate against.
+ * @param[out] property Pointer to store the extracted UTF-8 string pointer.
+ * @param[out] propertyLength Pointer to store the length of the extracted string.
+ *
+ * @return #MQTTSuccess if the property is successfully extracted;
+ * #MQTTBadParameter if parameters are invalid or property ID doesn't match.
+ */
+static MQTTStatus_t getPropUtf8( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ const char ** property,
+ size_t * propertyLength );
+
+/*-----------------------------------------------------------*/
+
+static inline MQTTStatus_t checkPropBuilderParams( MQTTPropBuilder_t * mqttPropBuilder,
+ size_t * currentIndex )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( ( mqttPropBuilder == NULL ) || ( mqttPropBuilder->pBuffer == NULL ) ||
+ ( currentIndex == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( *currentIndex >= mqttPropBuilder->currentIndex )
+ {
+ LogWarn( ( "Index out of bounds." ) );
+ status = MQTTEndOfProperties;
+ }
+ else
+ {
+ /* Nothing to do. All good. */
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t getPropUint8( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint8_t * property )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( property == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t localPropertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == localPropertyId )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ uint32_t remainingPropLength = ( uint32_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+ bool tempBool = false;
+
+ pLocalIndex++;
+
+ status = decodeUint8t( property,
+ &remainingPropLength,
+ &tempBool,
+ &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not %" PRIu8, propertyId ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t getPropUint16( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint16_t * property )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( property == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t localPropertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == localPropertyId )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ /* Remaining properties = Total properties - current location in the buffer - 1 ( for property ID ). */
+ uint32_t remainingPropLength = ( uint32_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+ bool tempBool = false;
+
+ /* Move index to the beginning of the key. */
+ pLocalIndex++;
+
+ status = decodeUint16t( property,
+ &remainingPropLength,
+ &tempBool,
+ &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ /* Move the index to the end of the property. */
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not %" PRIu8, propertyId ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t getPropUint32( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ uint32_t * property )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( property == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t localPropertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == localPropertyId )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ /* Remaining properties = Total properties - current location in the buffer - 1 ( for property ID ). */
+ uint32_t remainingPropLength = ( uint32_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+ bool tempBool = false;
+
+ /* Move index to the beginning of the key. */
+ pLocalIndex++;
+
+ status = decodeUint32t( property,
+ &remainingPropLength,
+ &tempBool,
+ &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ /* Move the index to the end of the property. */
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not %" PRIu8 ".", propertyId ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t getPropUtf8( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t propertyId,
+ const char ** property,
+ size_t * propertyLength )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( ( property == NULL ) || ( propertyLength == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t localPropertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == localPropertyId )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ uint32_t remainingPropLength = ( uint32_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+ bool tempBool = false;
+
+ pLocalIndex++;
+
+ status = decodeUtf8( property,
+ propertyLength,
+ &remainingPropLength,
+ &tempBool,
+ &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not %" PRIu8 ".", propertyId ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetNextPropertyType( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * property )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ /* Do nothing. checkPropBuilderParams will log the warning/error. */
+ }
+ else if( property == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ *property = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ switch( *property )
+ {
+ case MQTT_SESSION_EXPIRY_ID:
+ case MQTT_RECEIVE_MAX_ID:
+ case MQTT_MAX_PACKET_SIZE_ID:
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+ case MQTT_REQUEST_RESPONSE_ID:
+ case MQTT_REQUEST_PROBLEM_ID:
+ case MQTT_USER_PROPERTY_ID:
+ case MQTT_AUTH_METHOD_ID:
+ case MQTT_AUTH_DATA_ID:
+ case MQTT_WILL_DELAY_ID:
+ case MQTT_PAYLOAD_FORMAT_ID:
+ case MQTT_MSG_EXPIRY_ID:
+ case MQTT_CONTENT_TYPE_ID:
+ case MQTT_RESPONSE_TOPIC_ID:
+ case MQTT_CORRELATION_DATA_ID:
+ case MQTT_TOPIC_ALIAS_ID:
+ case MQTT_MAX_QOS_ID:
+ case MQTT_RETAIN_AVAILABLE_ID:
+ case MQTT_ASSIGNED_CLIENT_ID:
+ case MQTT_REASON_STRING_ID:
+ case MQTT_WILDCARD_ID:
+ case MQTT_SUB_AVAILABLE_ID:
+ case MQTT_SHARED_SUB_ID:
+ case MQTT_SERVER_KEEP_ALIVE_ID:
+ case MQTT_RESPONSE_INFO_ID:
+ case MQTT_SERVER_REF_ID:
+ case MQTT_SUBSCRIPTION_ID_ID:
+ break;
+
+ default:
+ LogError( ( "Unknown property ID: %d", *property ) );
+ status = MQTTBadParameter;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SkipNextProperty( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+ uint8_t property;
+ uint8_t * pLocalIndex;
+ uint32_t remainingPropLength;
+ bool tempBool = false;
+ uint32_t dummyUint32;
+ uint16_t dummyUint16;
+ uint8_t dummyUint8;
+ const char * dummyString;
+ size_t dummyStringLen;
+
+ if( status != MQTTSuccess )
+ {
+ /* Do nothing. checkPropBuilderParams will log the warning/error. */
+ }
+ else
+ {
+ property = pPropertyBuilder->pBuffer[ *currentIndex ];
+ pLocalIndex = &pPropertyBuilder->pBuffer[ *currentIndex ];
+ remainingPropLength = pPropertyBuilder->currentIndex - *currentIndex - 1U;
+
+ /* Skip the property ID byte */
+ pLocalIndex++;
+
+ switch( property )
+ {
+ /* Four-byte integer properties */
+ case MQTT_SESSION_EXPIRY_ID:
+ case MQTT_MAX_PACKET_SIZE_ID:
+ case MQTT_WILL_DELAY_ID:
+ case MQTT_MSG_EXPIRY_ID:
+ status = decodeUint32t( &dummyUint32, &remainingPropLength, &tempBool, &pLocalIndex );
+ break;
+
+ /* Two-byte integer properties */
+ case MQTT_RECEIVE_MAX_ID:
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+ case MQTT_TOPIC_ALIAS_ID:
+ case MQTT_SERVER_KEEP_ALIVE_ID:
+ status = decodeUint16t( &dummyUint16, &remainingPropLength, &tempBool, &pLocalIndex );
+ break;
+
+ /* One-byte integer properties */
+ case MQTT_REQUEST_RESPONSE_ID:
+ case MQTT_REQUEST_PROBLEM_ID:
+ case MQTT_PAYLOAD_FORMAT_ID:
+ case MQTT_MAX_QOS_ID:
+ case MQTT_RETAIN_AVAILABLE_ID:
+ case MQTT_WILDCARD_ID:
+ case MQTT_SUB_AVAILABLE_ID:
+ case MQTT_SHARED_SUB_ID:
+ status = decodeUint8t( &dummyUint8, &remainingPropLength, &tempBool, &pLocalIndex );
+ break;
+
+ /* UTF-8 string properties */
+ case MQTT_AUTH_METHOD_ID:
+ case MQTT_CONTENT_TYPE_ID:
+ case MQTT_RESPONSE_TOPIC_ID:
+ case MQTT_ASSIGNED_CLIENT_ID:
+ case MQTT_REASON_STRING_ID:
+ case MQTT_RESPONSE_INFO_ID:
+ case MQTT_SERVER_REF_ID:
+ case MQTT_AUTH_DATA_ID:
+ case MQTT_CORRELATION_DATA_ID:
+ status = decodeUtf8( &dummyString, &dummyStringLen, &remainingPropLength, &tempBool, &pLocalIndex );
+ break;
+
+ /* User property (two UTF-8 strings: key and value) */
+ case MQTT_USER_PROPERTY_ID:
+ status = decodeUserProp( &dummyString, &dummyStringLen,
+ &dummyString, &dummyStringLen,
+ &remainingPropLength, &pLocalIndex );
+ break;
+
+ /* Variable byte integer property (subscription identifier) */
+ case MQTT_SUBSCRIPTION_ID_ID:
+ {
+ uint32_t subscriptionId;
+ size_t varIntSize;
+
+ status = decodeVariableLength( pLocalIndex, remainingPropLength, &subscriptionId );
+
+ if( status == MQTTSuccess )
+ {
+ varIntSize = variableLengthEncodedSize( subscriptionId );
+ pLocalIndex = &pLocalIndex[ varIntSize ];
+ }
+ }
+ break;
+
+ default:
+ LogError( ( "Unknown property ID: %d", property ) );
+ status = MQTTBadParameter;
+ break;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Update the current index to point past the skipped property */
+ *currentIndex = ( uint32_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_UserProp( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ MQTTUserProperty_t * pUserProperty )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( pUserProperty == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t propertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == MQTT_USER_PROPERTY_ID )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ /* Remaining properties = Total properties - current location in the buffer - 1 ( for property ID ). */
+ uint32_t remainingPropLength = ( uint32_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+
+ /* Move index to the beginning of the key. */
+ pLocalIndex++;
+
+ status = decodeUserProp( &pUserProperty->pKey,
+ &pUserProperty->keyLength,
+ &pUserProperty->pValue,
+ &pUserProperty->valueLength,
+ &remainingPropLength,
+ &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ /* Move the index to the end of the property. */
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not a User Property." ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_SessionExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pSessionExpiry )
+{
+ return getPropUint32( pPropertyBuilder, currentIndex, MQTT_SESSION_EXPIRY_ID, pSessionExpiry );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ReceiveMax( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pReceiveMax )
+{
+ return getPropUint16( pPropertyBuilder, currentIndex, MQTT_RECEIVE_MAX_ID, pReceiveMax );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_MaxQos( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pMaxQos )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_MAX_QOS_ID, pMaxQos );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_RetainAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pRetainAvailable )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_RETAIN_AVAILABLE_ID, pRetainAvailable );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_MaxPacketSize( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pMaxPacketSize )
+{
+ return getPropUint32( pPropertyBuilder, currentIndex, MQTT_MAX_PACKET_SIZE_ID, pMaxPacketSize );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_AssignedClientId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pClientId,
+ size_t * pClientIdLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_ASSIGNED_CLIENT_ID, pClientId, pClientIdLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_TopicAliasMax( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pTopicAliasMax )
+{
+ return getPropUint16( pPropertyBuilder, currentIndex, MQTT_TOPIC_ALIAS_MAX_ID, pTopicAliasMax );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ReasonString( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pReasonString,
+ size_t * pReasonStringLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_REASON_STRING_ID, pReasonString, pReasonStringLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_WildcardId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pWildcardAvailable )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_WILDCARD_ID, pWildcardAvailable );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_SubsIdAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pSubsIdAvailable )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_SUB_AVAILABLE_ID, pSubsIdAvailable );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_SharedSubAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pSharedSubAvailable )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_SHARED_SUB_ID, pSharedSubAvailable );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ServerKeepAlive( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pServerKeepAlive )
+{
+ return getPropUint16( pPropertyBuilder, currentIndex, MQTT_SERVER_KEEP_ALIVE_ID, pServerKeepAlive );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ResponseInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pResponseInfo,
+ size_t * pResponseInfoLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_RESPONSE_INFO_ID, pResponseInfo, pResponseInfoLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ServerRef( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pServerRef,
+ size_t * pServerRefLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_SERVER_REF_ID, pServerRef, pServerRefLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_AuthMethod( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pAuthMethod,
+ size_t * pAuthMethodLen )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_AUTH_METHOD_ID, pAuthMethod, pAuthMethodLen );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_AuthData( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pAuthData,
+ size_t * pAuthDataLen )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_AUTH_DATA_ID, pAuthData, pAuthDataLen );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_PayloadFormatIndicator( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pPayloadFormat )
+{
+ return getPropUint8( pPropertyBuilder, currentIndex, MQTT_PAYLOAD_FORMAT_ID, pPayloadFormat );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_MessageExpiryInterval( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pMessageExpiry )
+{
+ return getPropUint32( pPropertyBuilder, currentIndex, MQTT_MSG_EXPIRY_ID, pMessageExpiry );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_TopicAlias( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pTopicAlias )
+{
+ return getPropUint16( pPropertyBuilder, currentIndex, MQTT_TOPIC_ALIAS_ID, pTopicAlias );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ResponseTopic( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pResponseTopic,
+ size_t * pResponseTopicLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_RESPONSE_TOPIC_ID, pResponseTopic, pResponseTopicLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_CorrelationData( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pCorrelationData,
+ size_t * pCorrelationDataLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_CORRELATION_DATA_ID, pCorrelationData, pCorrelationDataLength );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_SubscriptionId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pSubscriptionId )
+{
+ MQTTStatus_t status = checkPropBuilderParams( pPropertyBuilder, currentIndex );
+
+ if( status != MQTTSuccess )
+ {
+ LogError( ( "Property type is invalid." ) );
+ }
+ else if( pSubscriptionId == NULL )
+ {
+ LogError( ( "Argument cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t propertyId = pPropertyBuilder->pBuffer[ *currentIndex ];
+
+ if( propertyId == MQTT_SUBSCRIPTION_ID_ID )
+ {
+ uint8_t * pLocalIndex = ( uint8_t * ) &pPropertyBuilder->pBuffer[ *currentIndex ];
+ size_t remainingPropLength = ( size_t ) ( pPropertyBuilder->currentIndex - *currentIndex - 1U );
+
+ pLocalIndex++;
+
+ status = decodeVariableLength( pLocalIndex, remainingPropLength, pSubscriptionId );
+
+ if( status == MQTTSuccess )
+ {
+ size_t encodedSize = variableLengthEncodedSize( *pSubscriptionId );
+ pLocalIndex = &pLocalIndex[ encodedSize ];
+ *currentIndex = ( size_t ) ( pLocalIndex - pPropertyBuilder->pBuffer );
+ }
+ }
+ else
+ {
+ LogError( ( "Property is not a Subscription Identifier Property." ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropGet_ContentType( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pContentType,
+ size_t * pContentTypeLength )
+{
+ return getPropUtf8( pPropertyBuilder, currentIndex, MQTT_CONTENT_TYPE_ID, pContentType, pContentTypeLength );
+}
+
+/*-----------------------------------------------------------*/
diff --git a/source/core_mqtt_prop_serializer.c b/source/core_mqtt_prop_serializer.c
new file mode 100644
index 000000000..33b895db7
--- /dev/null
+++ b/source/core_mqtt_prop_serializer.c
@@ -0,0 +1,1149 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_prop_serializer.c
+ * @brief Implements the user-facing functions to serialize user-properties.
+ */
+#include
+#include
+#include
+#include
+
+#include "core_mqtt_serializer.h"
+
+#include "private/core_mqtt_serializer_private.h"
+
+/* Include config defaults header to get default values of configs. */
+#include "core_mqtt_config_defaults.h"
+
+/**
+ * @brief Check whether the provided property is allowed for a packet type.
+ *
+ * @param[in] mqttPacketType Packet type to check.
+ * @param[in] propBitLocation Bit location of the property.
+ *
+ * @return Whether the property is allowed for the packet type.
+ */
+static bool isValidPropertyInPacketType( const uint8_t * mqttPacketType,
+ uint8_t propBitLocation );
+
+/**
+ * @brief Add a uint8 property to the property builder.
+ *
+ * This function adds a uint8 property to the property builder with validation
+ * for packet type compatibility and buffer space.
+ *
+ * @param[in,out] pPropertyBuilder Pointer to the property builder to add the property to.
+ * @param[in] property The uint8 property value to add.
+ * @param[in] propId The property ID for this property.
+ * @param[in] fieldPosition The bit position in the fieldSet for duplicate checking.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for validation.
+ * Can be NULL to skip packet type validation.
+ *
+ * @return #MQTTSuccess if the property is successfully added;
+ * #MQTTBadParameter if parameters are invalid;
+ * #MQTTNoMemory if insufficient buffer space.
+ */
+static MQTTStatus_t addPropUint8( MQTTPropBuilder_t * pPropertyBuilder,
+ uint8_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType );
+
+/**
+ * @brief Add a uint16 property to the property builder.
+ *
+ * This function adds a uint16 property to the property builder with validation
+ * for packet type compatibility and buffer space.
+ *
+ * @param[in,out] pPropertyBuilder Pointer to the property builder to add the property to.
+ * @param[in] property The uint16 property value to add.
+ * @param[in] propId The property ID for this property.
+ * @param[in] fieldPosition The bit position in the fieldSet for duplicate checking.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for validation.
+ * Can be NULL to skip packet type validation.
+ *
+ * @return #MQTTSuccess if the property is successfully added;
+ * #MQTTBadParameter if parameters are invalid;
+ * #MQTTNoMemory if insufficient buffer space.
+ */
+static MQTTStatus_t addPropUint16( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType );
+
+/**
+ * @brief Add a uint32 property to the property builder.
+ *
+ * This function adds a uint32 property to the property builder with validation
+ * for packet type compatibility and buffer space.
+ *
+ * @param[in,out] pPropertyBuilder Pointer to the property builder to add the property to.
+ * @param[in] property The uint32 property value to add.
+ * @param[in] propId The property ID for this property.
+ * @param[in] fieldPosition The bit position in the fieldSet for duplicate checking.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for validation.
+ * Can be NULL to skip packet type validation.
+ *
+ * @return #MQTTSuccess if the property is successfully added;
+ * #MQTTBadParameter if parameters are invalid;
+ * #MQTTNoMemory if insufficient buffer space.
+ */
+static MQTTStatus_t addPropUint32( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType );
+
+/**
+ * @brief Add a UTF-8 string property to the property builder.
+ *
+ * This function adds a UTF-8 string property to the property builder with validation
+ * for packet type compatibility and buffer space.
+ *
+ * @param[in,out] pPropertyBuilder Pointer to the property builder to add the property to.
+ * @param[in] property The UTF-8 string property value to add.
+ * @param[in] propertyLength The length of the UTF-8 string property.
+ * @param[in] propId The property ID for this property.
+ * @param[in] fieldPosition The bit position in the fieldSet for duplicate checking.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for validation.
+ * Can be NULL to skip packet type validation.
+ *
+ * @return #MQTTSuccess if the property is successfully added;
+ * #MQTTBadParameter if parameters are invalid;
+ * #MQTTNoMemory if insufficient buffer space.
+ */
+static MQTTStatus_t addPropUtf8( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * property,
+ size_t propertyLength,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType );
+
+/*-----------------------------------------------------------*/
+
+static bool isValidPropertyInPacketType( const uint8_t * mqttPacketType,
+ uint8_t propBitLocation )
+{
+ bool isAllowed = false;
+ uint32_t allowedPropertiesMask = 0U;
+
+ switch( *mqttPacketType )
+ {
+ case MQTT_PACKET_TYPE_CONNECT:
+
+ /* CONNECT properties:
+ * - Session Expiry Interval
+ * - Receive Maximum
+ * - Maximum Packet Size
+ * - Topic Alias Maximum
+ * - Request Response Information
+ * - Request Problem Information
+ * - User Property
+ * - Authentication Method
+ * - Authentication Data
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RECEIVE_MAXIMUM_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_MAX_PACKET_SIZE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_TOPIC_ALIAS_MAX_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REQUEST_RESPONSE_INFO_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REQUEST_PROBLEM_INFO_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_METHOD_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_DATA_POS );
+
+ /* Will properties. */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_WILL_DELAY_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_PAYLOAD_FORMAT_INDICATOR_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_MESSAGE_EXPIRY_INTERVAL_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_CONTENT_TYPE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RESPONSE_TOPIC_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_CORRELATION_DATA_POS );
+
+ break;
+
+ case MQTT_PACKET_TYPE_CONNACK:
+
+ /* CONNACK properties:
+ * - Session Expiry Interval
+ * - Receive Maximum
+ * - Maximum QoS
+ * - Retain Available
+ * - Maximum Packet Size
+ * - Assigned Client Identifier
+ * - Topic Alias Maximum
+ * - Reason String
+ * - User Property
+ * - Wildcard Subscription Available
+ * - Subscription Identifier Available
+ * - Shared Subscription Available
+ * - Server Keep Alive
+ * - Response Information
+ * - Server Reference
+ * - Authentication Method
+ * - Authentication Data
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RECEIVE_MAXIMUM_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_MAX_QOS_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RETAIN_AVAILABLE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_MAX_PACKET_SIZE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_ASSIGNED_CLIENT_ID_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_TOPIC_ALIAS_MAX_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_WILDCARD_SUBSCRIPTION_AVAILABLE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SUBSCRIPTION_ID_AVAILABLE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SHARED_SUBSCRIPTION_AVAILABLE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SERVER_KEEP_ALIVE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RESPONSE_INFORMATION_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SERVER_REFERENCE_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_METHOD_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_DATA_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_PUBLISH:
+
+ /* PUBLISH properties:
+ * - Payload Format Indicator
+ * - Message Expiry Interval
+ * - Topic Alias
+ * - Response Topic
+ * - Correlation Data
+ * - User Property
+ * - Subscription Identifier (only in server-to-client PUBLISH)
+ * - Content Type
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_PAYLOAD_FORMAT_INDICATOR_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_MESSAGE_EXPIRY_INTERVAL_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_TOPIC_ALIAS_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_RESPONSE_TOPIC_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_CORRELATION_DATA_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SUBSCRIPTION_ID_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_CONTENT_TYPE_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_PUBACK:
+ case MQTT_PACKET_TYPE_PUBREC:
+ case MQTT_PACKET_TYPE_PUBREL:
+ case MQTT_PACKET_TYPE_PUBCOMP:
+
+ /* PUBACK, PUBREC, PUBREL, PUBCOMP properties:
+ * - Reason String
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_SUBSCRIBE:
+
+ /* SUBSCRIBE properties:
+ * - Subscription Identifier
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SUBSCRIPTION_ID_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_SUBACK:
+
+ /* SUBACK properties:
+ * - Reason String
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_UNSUBSCRIBE:
+
+ /* UNSUBSCRIBE properties:
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_UNSUBACK:
+
+ /* UNSUBACK properties:
+ * - Reason String
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_DISCONNECT:
+
+ /* DISCONNECT properties:
+ * - Session Expiry Interval
+ * - Reason String
+ * - User Property
+ * - Server Reference
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_SERVER_REFERENCE_POS );
+ break;
+
+ case MQTT_PACKET_TYPE_PINGREQ:
+ case MQTT_PACKET_TYPE_PINGRESP:
+
+ /* PINGREQ and PINGRESP have no properties section.
+ * allowedPropertiesMask remains 0. */
+ break;
+
+ case MQTT_PACKET_TYPE_AUTH:
+
+ /* AUTH properties:
+ * - Authentication Method
+ * - Authentication Data
+ * - Reason String
+ * - User Property
+ */
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_METHOD_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_AUTHENTICATION_DATA_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_REASON_STRING_POS );
+ UINT32_SET_BIT( allowedPropertiesMask, MQTT_USER_PROP_POS );
+
+ default:
+ /* Unknown packet type - no properties allowed. */
+ break;
+ }
+
+ /* Check if the property bit is set in the allowed mask. */
+ isAllowed = UINT32_CHECK_BIT( allowedPropertiesMask, propBitLocation );
+
+ return isAllowed;
+}
+
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t addPropUint8( MQTTPropBuilder_t * pPropertyBuilder,
+ uint8_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ uint8_t * pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "pPropertyBuilder cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "pPropertyBuilder->pBuffer cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, fieldPosition ) )
+ {
+ LogError( ( "%" PRIu8 " already set.", propId ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, fieldPosition ) == false ) )
+ {
+ LogError( ( "%" PRIu8 " not allowed in %d packet type.", propId, *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+ /* We need 1 byte to encode the property and 1 byte to encode the property ID. */
+ else if( ( pPropertyBuilder->bufferLength < 2U ) ||
+ ( pPropertyBuilder->currentIndex > ( pPropertyBuilder->bufferLength - 2U ) ) )
+ {
+ LogError( ( "Buffer too small to add property" ) );
+ status = MQTTNoMemory;
+ }
+ else if( pPropertyBuilder->currentIndex > ( MQTT_REMAINING_LENGTH_INVALID - 2U ) )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ *pIndex = propId;
+ pIndex++;
+ *pIndex = ( property ? 1U : 0U );
+ UINT32_SET_BIT( pPropertyBuilder->fieldSet, fieldPosition );
+ pPropertyBuilder->currentIndex += 2U;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t addPropUint16( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, fieldPosition ) )
+ {
+ LogError( ( "%" PRIu8 " already set.", propId ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, fieldPosition ) == false ) )
+ {
+ LogError( ( "Receive Maximum not allowed in %d packet type.", *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+
+ /* We need 1 byte to encode property ID and 2 bytes to encode the property
+ * itself. */
+ else if( ( pPropertyBuilder->bufferLength < 3U ) ||
+ ( pPropertyBuilder->currentIndex > ( pPropertyBuilder->bufferLength - 3U ) ) )
+ {
+ LogError( ( "Buffer too small to add property." ) );
+ status = MQTTNoMemory;
+ }
+ else if( pPropertyBuilder->currentIndex > ( MQTT_REMAINING_LENGTH_INVALID - 3U ) )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ uint8_t * pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ *pIndex = propId;
+ pIndex++;
+ pIndex[ 0 ] = UINT16_HIGH_BYTE( property );
+ pIndex[ 1 ] = UINT16_LOW_BYTE( property );
+
+ UINT32_SET_BIT( pPropertyBuilder->fieldSet, fieldPosition );
+ pPropertyBuilder->currentIndex += 3U;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t addPropUint32( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t property,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pIndex;
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, fieldPosition ) )
+ {
+ LogError( ( "Subscription Id already set." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, fieldPosition ) == false ) )
+ {
+ LogError( ( "Subscription Id not allowed in %d packet type.", *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+
+ /* We need 1 byte to encode property ID and 4 bytes to encode the property
+ * itself. */
+ else if( ( pPropertyBuilder->bufferLength < 5U ) ||
+ ( pPropertyBuilder->currentIndex > ( pPropertyBuilder->bufferLength - 5U ) ) )
+ {
+ LogError( ( "Buffer too small to add subscription id." ) );
+ status = MQTTNoMemory;
+ }
+ else if( pPropertyBuilder->currentIndex > ( MQTT_REMAINING_LENGTH_INVALID - 5U ) )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ *pIndex = propId;
+ pIndex++;
+ WRITE_UINT32( &( pIndex[ 0 ] ), property );
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pPropertyBuilder->currentIndex += 5U;
+ UINT32_SET_BIT( pPropertyBuilder->fieldSet, fieldPosition );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t addPropUtf8( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * property,
+ size_t propertyLength,
+ uint8_t propId,
+ uint8_t fieldPosition,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ uint8_t * pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( propertyLength ) );
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( property == NULL )
+ {
+ LogError( ( "property cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( propertyLength == 0U )
+ {
+ LogError( ( "Property Length cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, fieldPosition ) )
+ {
+ LogError( ( "Reason String already set." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, fieldPosition ) == false ) )
+ {
+ LogError( ( "Reason String not allowed in %d packet type.", *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+
+ /* We need to make sure that adding 2 to property length will not overflow. Then, we need to make
+ * sure that buffer is greater than the size needed to fit the property ( 2U + property length ).
+ * Then, we need to make sure that buffer is big enough to handle the existing data and this property. */
+ else if( ADDITION_WILL_OVERFLOW_SIZE_T( propertyLength, 2U ) ||
+ ( pPropertyBuilder->bufferLength < ( propertyLength + 2U ) ) ||
+ ( pPropertyBuilder->currentIndex > ( pPropertyBuilder->bufferLength - ( propertyLength + 2U ) ) ) )
+ {
+ LogError( ( "Buffer too small to add property." ) );
+ status = MQTTNoMemory;
+ }
+ else if( ( MQTT_REMAINING_LENGTH_INVALID < ( propertyLength + 2U ) ) ||
+ ( pPropertyBuilder->currentIndex > ( MQTT_REMAINING_LENGTH_INVALID - ( propertyLength + 2U ) ) ) )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ *pIndex = propId;
+ pIndex++;
+ pIndex = encodeString( pIndex, property, propertyLength );
+ UINT32_SET_BIT( pPropertyBuilder->fieldSet, fieldPosition );
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pPropertyBuilder->currentIndex += ( size_t ) ( pIndex - ( &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ] ) );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_SubscriptionId( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t subscriptionId,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pIndex;
+
+ if( subscriptionId == 0U )
+ {
+ LogError( ( "Subscription Id cannot be 0 for subscribe properties: Protocol Error." ) );
+ status = MQTTBadParameter;
+ }
+ else if( subscriptionId > MAX_VARIABLE_LENGTH_INT_VALUE )
+ {
+ LogError( ( "Subscription Id cannot be greater than 268435455: Protocol Error." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, MQTT_SUBSCRIPTION_ID_POS ) )
+ {
+ LogError( ( "Subscription Id already set." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, MQTT_SUBSCRIPTION_ID_POS ) == false ) )
+ {
+ LogError( ( "Subscription Id not allowed in %d packet type.", *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+ /* variableLengthEncodedSize always returns a number in the range of [1,4]. The addition will not overflow. */
+ else if( ( pPropertyBuilder->bufferLength < ( variableLengthEncodedSize( subscriptionId ) + 1U ) ) ||
+ ( pPropertyBuilder->currentIndex > pPropertyBuilder->bufferLength - ( variableLengthEncodedSize( subscriptionId ) + 1U ) ) )
+ {
+ LogError( ( "Buffer too small to add subscription id." ) );
+ status = MQTTNoMemory;
+ }
+ else if( pPropertyBuilder->currentIndex > ( MQTT_REMAINING_LENGTH_INVALID - ( variableLengthEncodedSize( subscriptionId ) + 1U ) ) )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ *pIndex = MQTT_SUBSCRIPTION_ID_ID;
+ pIndex++;
+ pIndex = encodeVariableLength( pIndex, subscriptionId );
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pPropertyBuilder->currentIndex += ( size_t ) ( pIndex - &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ] );
+ UINT32_SET_BIT( pPropertyBuilder->fieldSet, MQTT_SUBSCRIPTION_ID_POS );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_UserProp( MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTUserProperty_t * userProperty,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "Argument pPropertyBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( userProperty == NULL )
+ {
+ LogError( ( "Argument userProperty cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( userProperty->pKey == NULL ) ||
+ ( userProperty->pValue == NULL ) ||
+ ( userProperty->keyLength == 0U ) ||
+ ( userProperty->valueLength == 0U ) )
+ {
+ LogError( ( "Arguments cannot be NULL: pUserProperties->userProperty->pKey=%p, "
+ "pUserProperties->userProperty->pValue=%p, "
+ "Key Length = %d, Value Length = %d",
+ ( void * ) userProperty->pKey,
+ ( void * ) userProperty->pValue,
+ ( int ) userProperty->keyLength,
+ ( int ) userProperty->valueLength ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pOptionalMqttPacketType != NULL ) &&
+ ( isValidPropertyInPacketType( pOptionalMqttPacketType, MQTT_USER_PROP_POS ) == false ) )
+ {
+ LogError( ( "User property not allowed in %d packet type.", *pOptionalMqttPacketType ) );
+ status = MQTTBadParameter;
+ }
+ /* 1 byte Property ID + 2 byte key length + 2 byte value length. */
+ else if( ADDITION_WILL_OVERFLOW_SIZE_T( pPropertyBuilder->currentIndex, 5U ) )
+ {
+ LogError( ( "Property builder buffer will overflow." ) );
+ status = MQTTBadParameter;
+ }
+ /* 1 byte Property ID + 2 byte key length + 2 byte value length + Actual key */
+ else if( ADDITION_WILL_OVERFLOW_SIZE_T( pPropertyBuilder->currentIndex + 5U, userProperty->keyLength ) )
+ {
+ LogError( ( "Property builder buffer will overflow." ) );
+ status = MQTTBadParameter;
+ }
+ /* 1 byte Property ID + 2 byte key length + 2 byte value length + Actual key + Actual value. */
+ else if( ADDITION_WILL_OVERFLOW_SIZE_T( pPropertyBuilder->currentIndex + 5U + userProperty->keyLength,
+ userProperty->valueLength ) )
+ {
+ LogError( ( "Property builder buffer will overflow." ) );
+ status = MQTTBadParameter;
+ }
+
+ /*
+ * User property is encoded as a key-value pair of UTF-8 strings.
+ * 2-bytes for string length of key + key length +
+ * 2-bytes for string length of value + value length +
+ * 1 byte for property identifier.
+ */
+ else if( ( pPropertyBuilder->currentIndex +
+ sizeof( uint16_t ) + userProperty->keyLength +
+ sizeof( uint16_t ) + userProperty->valueLength +
+ sizeof( uint8_t ) ) > pPropertyBuilder->bufferLength )
+ {
+ LogError( ( "Buffer too small to add property." ) );
+ status = MQTTNoMemory;
+ }
+ else if( ( pPropertyBuilder->currentIndex +
+ sizeof( uint16_t ) + userProperty->keyLength +
+ sizeof( uint16_t ) + userProperty->valueLength +
+ sizeof( uint8_t ) ) > MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "MQTT packets must be smaller than %" PRIu32 ".",
+ ( uint32_t ) MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ const uint8_t * start = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+ uint8_t * pIndex = &pPropertyBuilder->pBuffer[ pPropertyBuilder->currentIndex ];
+
+ *pIndex = MQTT_USER_PROPERTY_ID;
+ pIndex++;
+
+ /* Encoding key. */
+ pIndex = encodeString( pIndex, userProperty->pKey, userProperty->keyLength );
+ pIndex = encodeString( pIndex, userProperty->pValue, userProperty->valueLength );
+ /* More details at: https://github.com/FreeRTOS/coreMQTT/blob/main/MISRA.md#rule-108 */
+ /* coverity[misra_c_2012_rule_10_8_violation] */
+ pPropertyBuilder->currentIndex += ( size_t ) ( pIndex - start );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_SessionExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t sessionExpiry,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ /* Any value of session expiry is valid. */
+ return addPropUint32( pPropertyBuilder,
+ sessionExpiry,
+ MQTT_SESSION_EXPIRY_ID,
+ MQTT_SESSION_EXPIRY_INTERVAL_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_ReceiveMax( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t receiveMax,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( receiveMax == 0U )
+ {
+ LogError( ( "Receive max cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = addPropUint16( pPropertyBuilder,
+ receiveMax,
+ MQTT_RECEIVE_MAX_ID,
+ MQTT_RECEIVE_MAXIMUM_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_MaxPacketSize( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t maxPacketSize,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( maxPacketSize == 0U )
+ {
+ LogError( ( "Max packet size cannot be set to 0." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = addPropUint32( pPropertyBuilder,
+ maxPacketSize,
+ MQTT_MAX_PACKET_SIZE_ID,
+ MQTT_MAX_PACKET_SIZE_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_TopicAliasMax( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t topicAliasMax,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ /* All values of topic alias maximum are valid. */
+ return addPropUint16( pPropertyBuilder,
+ topicAliasMax,
+ MQTT_TOPIC_ALIAS_MAX_ID,
+ MQTT_TOPIC_ALIAS_MAX_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_RequestRespInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ bool requestResponseInfo,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ return addPropUint8( pPropertyBuilder,
+ ( uint8_t ) requestResponseInfo,
+ MQTT_REQUEST_RESPONSE_ID,
+ MQTT_REQUEST_RESPONSE_INFO_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_RequestProbInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ bool requestProblemInfo,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ return addPropUint8( pPropertyBuilder,
+ ( uint8_t ) requestProblemInfo,
+ MQTT_REQUEST_PROBLEM_ID,
+ MQTT_REQUEST_PROBLEM_INFO_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_AuthMethod( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * authMethod,
+ size_t authMethodLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( CHECK_SIZE_T_OVERFLOWS_16BIT( authMethodLength ) )
+ {
+ LogError( ( "Auth method length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Auth method has no restrictions and hence no additional checks required. */
+ status = addPropUtf8( pPropertyBuilder,
+ authMethod,
+ authMethodLength,
+ MQTT_AUTH_METHOD_ID,
+ MQTT_AUTHENTICATION_METHOD_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_AuthData( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * authData,
+ size_t authDataLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pPropertyBuilder == NULL )
+ {
+ LogError( ( "pPropertyBuilder cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropertyBuilder->pBuffer == NULL )
+ {
+ LogError( ( "pPropertyBuilder->pBuffer cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( authData == NULL )
+ {
+ LogError( ( "authData cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( UINT32_CHECK_BIT( pPropertyBuilder->fieldSet, MQTT_AUTHENTICATION_METHOD_POS ) == false )
+ {
+ LogError( ( "Auth method must be added before authentication data. "
+ "Not a protocol violation but a practice enforced by coreMQTT." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( authDataLength ) )
+ {
+ LogError( ( "Auth data length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = addPropUtf8( pPropertyBuilder,
+ authData,
+ authDataLength,
+ MQTT_AUTH_DATA_ID,
+ MQTT_AUTHENTICATION_DATA_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_PayloadFormat( MQTTPropBuilder_t * pPropertyBuilder,
+ bool payloadFormat,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ return addPropUint8( pPropertyBuilder,
+ ( uint8_t ) payloadFormat,
+ MQTT_PAYLOAD_FORMAT_ID,
+ MQTT_PAYLOAD_FORMAT_INDICATOR_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_MessageExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t messageExpiry,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ return addPropUint32( pPropertyBuilder,
+ messageExpiry,
+ MQTT_MSG_EXPIRY_ID,
+ MQTT_MESSAGE_EXPIRY_INTERVAL_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_WillDelayInterval( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t willDelayInterval,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ return addPropUint32( pPropertyBuilder,
+ willDelayInterval,
+ MQTT_WILL_DELAY_ID,
+ MQTT_WILL_DELAY_POS,
+ pOptionalMqttPacketType );
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_TopicAlias( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t topicAlias,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( topicAlias == 0U )
+ {
+ LogError( ( "Topic Alias cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = addPropUint16( pPropertyBuilder,
+ topicAlias,
+ MQTT_TOPIC_ALIAS_ID,
+ MQTT_TOPIC_ALIAS_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_ResponseTopic( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * responseTopic,
+ size_t responseTopicLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( responseTopic == NULL )
+ {
+ LogError( ( "Arguments cannot be NULL : responseTopic=%p.", ( void * ) responseTopic ) );
+ status = MQTTBadParameter;
+ }
+ else if( responseTopicLength == 0U )
+ {
+ LogError( ( "Response Topic Length cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( memchr( ( void * ) responseTopic, ( int ) '#', responseTopicLength ) != NULL ) ||
+ ( memchr( ( void * ) responseTopic, ( int ) '+', responseTopicLength ) != NULL ) )
+ {
+ LogError( ( "Protocol Error : Response Topic contains wildcards (such as # or +)." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( responseTopicLength ) )
+ {
+ LogError( ( "Response topic length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ status = addPropUtf8( pPropertyBuilder,
+ responseTopic,
+ responseTopicLength,
+ MQTT_RESPONSE_TOPIC_ID,
+ MQTT_RESPONSE_TOPIC_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_CorrelationData( MQTTPropBuilder_t * pPropertyBuilder,
+ const void * pCorrelationData,
+ size_t correlationLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( CHECK_SIZE_T_OVERFLOWS_16BIT( correlationLength ) )
+ {
+ LogError( ( "Correlation data length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Encoding binary and UTF-8 strings behaves in the same way. */
+ status = addPropUtf8( pPropertyBuilder,
+ ( const char * ) pCorrelationData,
+ correlationLength,
+ MQTT_CORRELATION_DATA_ID,
+ MQTT_CORRELATION_DATA_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_ContentType( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * contentType,
+ size_t contentTypeLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( CHECK_SIZE_T_OVERFLOWS_16BIT( contentTypeLength ) )
+ {
+ LogError( ( "Content type string length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* No restriction and hence no additional checks on the content type. */
+ status = addPropUtf8( pPropertyBuilder,
+ contentType,
+ contentTypeLength,
+ MQTT_CONTENT_TYPE_ID,
+ MQTT_CONTENT_TYPE_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropAdd_ReasonString( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * pReasonString,
+ size_t reasonStringLength,
+ const uint8_t * pOptionalMqttPacketType )
+{
+ MQTTStatus_t status;
+
+ if( CHECK_SIZE_T_OVERFLOWS_16BIT( reasonStringLength ) )
+ {
+ LogError( ( "Reason string length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* No restriction and hence no additional checks on the reason string. */
+ status = addPropUtf8( pPropertyBuilder,
+ pReasonString,
+ reasonStringLength,
+ MQTT_REASON_STRING_ID,
+ MQTT_REASON_STRING_POS,
+ pOptionalMqttPacketType );
+ }
+
+ return status;
+}
diff --git a/source/core_mqtt_serializer.c b/source/core_mqtt_serializer.c
index f549ced5f..5da78398b 100644
--- a/source/core_mqtt_serializer.c
+++ b/source/core_mqtt_serializer.c
@@ -28,31 +28,22 @@
*/
#include
#include
+#include
+#include
+#include "core_mqtt.h"
#include "core_mqtt_serializer.h"
+#include "transport_interface.h"
+#include "private/core_mqtt_serializer_private.h"
/* Include config defaults header to get default values of configs. */
#include "core_mqtt_config_defaults.h"
-/**
- * @brief MQTT protocol version 3.1.1.
- */
-#define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U )
-
/**
* @brief Size of the fixed and variable header of a CONNECT packet.
*/
#define MQTT_PACKET_CONNECT_HEADER_SIZE ( 10UL )
-/* MQTT CONNECT flags. */
-#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */
-#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */
-#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS 1. */
-#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS 2. */
-#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */
-#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */
-#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief User name present. */
-
/*
* Positions of each flag in the first byte of an MQTT PUBLISH packet's
* fixed header.
@@ -63,101 +54,31 @@
#define MQTT_PUBLISH_FLAG_DUP ( 3 ) /**< @brief MQTT PUBLISH duplicate flag. */
/**
- * @brief The size of MQTT DISCONNECT packets, per MQTT spec.
- */
-#define MQTT_DISCONNECT_PACKET_SIZE ( 2UL )
-
-/**
- * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 3.1.1 spec.
+ * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 5.0 spec.
*/
#define MQTT_PACKET_PINGREQ_SIZE ( 2UL )
-/**
- * @brief The Remaining Length field of MQTT disconnect packets, per MQTT spec.
- */
-#define MQTT_DISCONNECT_REMAINING_LENGTH ( ( uint8_t ) 0 )
-
/*
- * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.
+ * Constants relating to CONNACK packets, defined by MQTT spec.
*/
-#define MQTT_PACKET_CONNACK_REMAINING_LENGTH ( ( uint8_t ) 2U ) /**< @brief A CONNACK packet always has a "Remaining length" of 2. */
#define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ( ( uint8_t ) 0x01U ) /**< @brief The "Session Present" bit is always the lowest bit. */
-/*
- * UNSUBACK, PUBACK, PUBREC, PUBREL, and PUBCOMP always have a remaining length
- * of 2.
- */
-#define MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief PUBACK, PUBREC, PUBREl, PUBCOMP, UNSUBACK Remaining length. */
-#define MQTT_PACKET_PINGRESP_REMAINING_LENGTH ( 0U ) /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */
-
-/**
- * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT
- * packet is this value, 256 MB.
- */
-#define MQTT_MAX_REMAINING_LENGTH ( 268435455UL )
-
-/**
- * @brief Set a bit in an 8-bit unsigned integer.
- */
-#define UINT8_SET_BIT( x, position ) ( ( x ) = ( uint8_t ) ( ( x ) | ( 0x01U << ( position ) ) ) )
-
-/**
- * @brief Clear a bit in an 8-bit unsigned integer.
- */
-#define UINT8_CLEAR_BIT( x, position ) ( ( x ) = ( uint8_t ) ( ( x ) & ( ~( 0x01U << ( position ) ) ) ) )
-
-/**
- * @brief Macro for checking if a bit is set in a 1-byte unsigned int.
- *
- * @param[in] x The unsigned int to check.
- * @param[in] position Which bit to check.
- */
-#define UINT8_CHECK_BIT( x, position ) ( ( ( x ) & ( 0x01U << ( position ) ) ) == ( 0x01U << ( position ) ) )
-
-/**
- * @brief Get the high byte of a 16-bit unsigned integer.
- */
-#define UINT16_HIGH_BYTE( x ) ( ( uint8_t ) ( ( x ) >> 8 ) )
-
-/**
- * @brief Get the low byte of a 16-bit unsigned integer.
- */
-#define UINT16_LOW_BYTE( x ) ( ( uint8_t ) ( ( x ) & 0x00ffU ) )
-
/**
- * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.
- *
- * @param[in] ptr A uint8_t* that points to the high byte.
- */
-#define UINT16_DECODE( ptr ) \
- ( uint16_t ) ( ( ( ( uint16_t ) ptr[ 0 ] ) << 8 ) | \
- ( ( uint16_t ) ptr[ 1 ] ) )
-
-/**
- * @brief A value that represents an invalid remaining length.
- *
- * This value is greater than what is allowed by the MQTT specification.
+ * @brief Minimum Length of PUBACK, PUBREC, PUBREL, PUBCOMP Packets
*/
-#define MQTT_REMAINING_LENGTH_INVALID ( ( size_t ) 268435456 )
+#define MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH ( ( uint8_t ) 2 )
/**
- * @brief The minimum remaining length for a QoS 0 PUBLISH.
- *
- * Includes two bytes for topic name length and one byte for topic name.
- */
-#define MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0 ( 3U )
-
-/*-----------------------------------------------------------*/
-
+ * @brief A PINGRESP packet always has a "Remaining length" of 0. */
+#define MQTT_PACKET_PINGRESP_REMAINING_LENGTH ( 0U )
/**
- * @brief MQTT Subscription packet types.
+ * @brief Minimum number of bytes in the CONNACK Packet.
+ * CONNECT Acknowledge Flags 0 + 1 = 1
+ * CONNECT Reason Code + 1 = 2
+ * Property Length byte (min) + 1 = 3
*/
-typedef enum MQTTSubscriptionType
-{
- MQTT_SUBSCRIBE, /**< @brief The type is a SUBSCRIBE packet. */
- MQTT_UNSUBSCRIBE /**< @brief The type is a UNSUBSCRIBE packet. */
-} MQTTSubscriptionType_t;
+#define MQTT_PACKET_CONNACK_MINIMUM_SIZE ( 3U )
/*-----------------------------------------------------------*/
@@ -168,16 +89,20 @@ typedef enum MQTTSubscriptionType
* Copy of the payload into the buffer is done as part of the serialization
* only if @p serializePayload is true.
*
- * @brief param[in] pPublishInfo Publish information.
- * @brief param[in] remainingLength Remaining length of the PUBLISH packet.
- * @brief param[in] packetIdentifier Packet identifier of PUBLISH packet.
- * @brief param[in, out] pFixedBuffer Buffer to which PUBLISH packet will be
+ * @param[in] pPublishInfo Publish information containing topic, QoS, payload and other
+ * PUBLISH packet fields.
+ * @param[in] pPublishProperties MQTT v5.0 properties for the PUBLISH packet. Can be NULL
+ * if no properties are needed.
+ * @param[in] remainingLength Remaining length of the PUBLISH packet.
+ * @param[in] packetIdentifier Packet identifier of PUBLISH packet.
+ * @param[in, out] pFixedBuffer Buffer to which PUBLISH packet will be
* serialized.
- * @brief param[in] serializePayload Copy payload to the serialized buffer
+ * @param[in] serializePayload Copy payload to the serialized buffer
* only if true. Only PUBLISH header will be serialized if false.
*/
static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pPublishProperties,
+ uint32_t remainingLength,
uint16_t packetIdentifier,
const MQTTFixedBuffer_t * pFixedBuffer,
bool serializePayload );
@@ -189,13 +114,18 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
* @param[in] pPublishInfo MQTT PUBLISH packet parameters.
* @param[out] pRemainingLength The Remaining Length of the MQTT PUBLISH packet.
* @param[out] pPacketSize The total size of the MQTT PUBLISH packet.
+ * @param[in] maxPacketSize Max packet size allowed by the server.
+ * @param[in] publishPropertyLength Length of the optional properties in MQTT_PUBLISH
*
- * @return false if the packet would exceed the size allowed by the
- * MQTT spec; true otherwise.
+ *
+ * @return MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec; MQTTSuccess otherwise.
*/
-static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize );
+static MQTTStatus_t calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ uint32_t publishPropertyLength );
/**
* @brief Calculates the packet size and remaining length of an MQTT
@@ -205,17 +135,23 @@ static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
* @param[out] pRemainingLength The Remaining Length of the MQTT SUBSCRIBE or
* UNSUBSCRIBE packet.
- * @param[out] pPacketSize The total size of the MQTT MQTT SUBSCRIBE or
- * UNSUBSCRIBE packet.
- * @param[in] subscriptionType #MQTT_SUBSCRIBE or #MQTT_UNSUBSCRIBE.
+ * @param[out] pPacketSize The total size of the MQTT SUBSCRIBE or
+ * MQTT UNSUBSCRIBE packet.
+ * @param[in] subscribePropLen Length of the optional properties in MQTT_SUBSCRIBE or MQTT_UNSUBSCRIBE
+ * @param[in] maxPacketSize Maximum Packet Size allowed by the broker
+ * @param[in] subscriptionType #MQTT_TYPE_SUBSCRIBE or #MQTT_TYPE_UNSUBSCRIBE.
+ *
+ * @return MQTTBadParameter if the packet would exceed the size allowed by the
+ * MQTT spec or a subscription is empty; MQTTSuccess otherwise.
*
- * #MQTTBadParameter if the packet would exceed the size allowed by the
- * MQTT spec or a subscription is empty; #MQTTSuccess otherwise.
*/
+
static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t subscribePropLen,
+ uint32_t maxPacketSize,
MQTTSubscriptionType_t subscriptionType );
/**
@@ -235,7 +171,7 @@ static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t *
static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/**
@@ -243,12 +179,16 @@ static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo
*
* @param[in] pConnectInfo MQTT CONNECT packet parameters.
* @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[in] pConnectProperties MQTT CONNECT properties.
+ * @param[in] pWillProperties MQTT Will properties.
* @param[in] remainingLength Remaining Length of MQTT CONNECT packet.
* @param[out] pFixedBuffer Buffer for packet serialization.
*/
static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/**
@@ -259,19 +199,6 @@ static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
*/
static void logConnackResponse( uint8_t responseCode );
-/**
- * @brief Encodes the remaining length of the packet using the variable length
- * encoding scheme provided in the MQTT v3.1.1 specification.
- *
- * @param[out] pDestination The destination buffer to store the encoded remaining
- * length.
- * @param[in] length The remaining length to encode.
- *
- * @return The location of the byte following the encoded value.
- */
-static uint8_t * encodeRemainingLength( uint8_t * pDestination,
- size_t length );
-
/**
* @brief Retrieve the size of the remaining length if it were to be encoded.
*
@@ -279,20 +206,7 @@ static uint8_t * encodeRemainingLength( uint8_t * pDestination,
*
* @return The size of the remaining length if it were to be encoded.
*/
-static size_t remainingLengthEncodedSize( size_t length );
-
-/**
- * @brief Encode a string whose size is at maximum 16 bits in length.
- *
- * @param[out] pDestination Destination buffer for the encoding.
- * @param[in] pSource The source string to encode.
- * @param[in] sourceLength The length of the source string to encode.
- *
- * @return A pointer to the end of the encoded string.
- */
-static uint8_t * encodeString( uint8_t * pDestination,
- const char * pSource,
- uint16_t sourceLength );
+static size_t remainingLengthEncodedSize( uint32_t length );
/**
* @brief Retrieves and decodes the Remaining Length from the network interface
@@ -303,8 +217,8 @@ static uint8_t * encodeString( uint8_t * pDestination,
*
* @return The Remaining Length of the incoming packet.
*/
-static size_t getRemainingLength( TransportRecv_t recvFunc,
- NetworkContext_t * pNetworkContext );
+static uint32_t getRemainingLength( TransportRecv_t recvFunc,
+ NetworkContext_t * pNetworkContext );
/**
* @brief Retrieves, decodes and stores the Remaining Length from the network
@@ -346,9 +260,9 @@ static bool incomingPacketValid( uint8_t packetType );
*
* @return #MQTTSuccess or #MQTTBadResponse.
*/
-static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
+static MQTTStatus_t checkPublishRemainingLength( uint32_t remainingLength,
MQTTQoS_t qos,
- size_t qos0Minimum );
+ uint32_t qos0Minimum );
/**
* @brief Process the flags of an incoming PUBLISH packet.
@@ -363,46 +277,47 @@ static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
MQTTPublishInfo_t * pPublishInfo );
/**
- * @brief Deserialize a CONNACK packet.
- *
- * Converts the packet from a stream of bytes to an #MQTTStatus_t.
+ * @brief Deserialize an MQTT CONNACK packet.
*
- * @param[in] pConnack Pointer to an MQTT packet struct representing a
- * CONNACK.
- * @param[out] pSessionPresent Whether a previous session was present.
+ * @param[out] pConnackProperties To store the deserialized connack properties.
+ * @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[out] pSessionPresent Whether a previous session was present.
+ * @param[out] pPropBuffer MQTTPropBuilder_t to store the deserialized properties.
*
- * @return #MQTTSuccess if CONNACK specifies that CONNECT was accepted;
- * #MQTTServerRefused if CONNACK specifies that CONNECT was rejected;
- * #MQTTBadResponse if the CONNACK packet doesn't follow MQTT spec.
+ * @return #MQTTBadParameter, #MQTTBadResponse, #MQTTSuccess, #MQTTServerRefused
*/
-static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
- bool * pSessionPresent );
+static MQTTStatus_t deserializeConnack( MQTTConnectionProperties_t * pConnackProperties,
+ const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropBuffer );
/**
* @brief Decode the status bytes of a SUBACK packet to a #MQTTStatus_t.
*
* @param[in] statusCount Number of status bytes in the SUBACK.
* @param[in] pStatusStart The first status byte in the SUBACK.
- *
+ * @param[out] pReasonCodes The #MQTTReasonCodeInfo_t to store reason codes for each topic filter.
* @return #MQTTSuccess, #MQTTServerRefused, or #MQTTBadResponse.
*/
static MQTTStatus_t readSubackStatus( size_t statusCount,
- const uint8_t * pStatusStart );
+ const uint8_t * pStatusStart,
+ MQTTReasonCodeInfo_t * pReasonCodes );
/**
- * @brief Deserialize a SUBACK packet.
- *
- * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
- * the packet identifier.
+ * @brief Deserialize an MQTT SUBACK / UNSUBACK packet.
*
- * @param[in] pSuback Pointer to an MQTT packet struct representing a SUBACK.
- * @param[out] pPacketIdentifier Packet ID of the SUBACK.
+ * @param[in] incomingPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[out] pPacketId The packet ID obtained from the buffer.
+ * @param[out] pReasonCodes Struct to store reason code(s) from the acknowledgment packet.
+ * Contains the success/failure status of the corresponding request.
+ * @param[out] pPropBuffer MQTTPropBuilder_t to store the deserialized properties.
*
- * @return #MQTTSuccess if SUBACK is valid; #MQTTBadResponse if SUBACK packet
- * doesn't follow the MQTT spec.
+ * @return #MQTTBadParameter, #MQTTBadResponse, #MQTTSuccess, #MQTTServerRefused
*/
-static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
- uint16_t * pPacketIdentifier );
+static MQTTStatus_t deserializeSubUnsubAck( const MQTTPacketInfo_t * incomingPacket,
+ uint16_t * pPacketId,
+ MQTTReasonCodeInfo_t * pReasonCodes,
+ MQTTPropBuilder_t * pPropBuffer );
/**
* @brief Deserialize a PUBLISH packet received from the server.
@@ -416,49 +331,331 @@ static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
* @param[out] pPacketId Packet identifier of the PUBLISH.
* @param[out] pPublishInfo Pointer to #MQTTPublishInfo_t where output is
* written.
+ * @param[out] pPropBuffer Pointer to the property buffer.
+ * @param[in] topicAliasMax Maximum allowed Topic Alias.
*
- * @return #MQTTSuccess if PUBLISH is valid; #MQTTBadResponse
- * if the PUBLISH packet doesn't follow MQTT spec.
+ * @return #MQTTSuccess if PUBLISH is valid;
+ * #MQTTBadResponse if the PUBLISH packet doesn't follow MQTT spec.
*/
static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- MQTTPublishInfo_t * pPublishInfo );
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * pPropBuffer,
+ uint16_t topicAliasMax );
+
+/**
+ * @brief Deserialize a PINGRESP packet.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t.
+ *
+ * @param[in] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.
+ *
+ * @return #MQTTSuccess if PINGRESP is valid; #MQTTBadResponse if the PINGRESP
+ * packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp );
+
+/**
+ * @brief Validate the connack parameters.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
+ * the variable header without connack properties.
+ *
+ * @param[in] pIncomingPacket Pointer to an MQTT packet struct representing a incoming packet.
+ * @param[out] pSessionPresent Whether a session is present or not.
+ *
+ *
+ * @return #MQTTSuccess if connack without connack properties is valid;
+ * #MQTTServerRefused if the server refused the connection;
+ * #MQTTBadResponse if the Connack packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t validateConnackParams( const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent );
+
+/**
+ * @brief Validate the length and decode the connack properties.
+ *
+ * @param[out] pConnackProperties To store the decoded property.
+ * @param[in] length Length of the properties.
+ * @param[in] pIndex Pointer to the start of the properties.
+ * @param[out] pPropBuffer Pointer to the property buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+static MQTTStatus_t deserializeConnackProperties( MQTTConnectionProperties_t * pConnackProperties,
+ uint32_t length,
+ uint8_t * pIndex,
+ MQTTPropBuilder_t * pPropBuffer );
+
+/**
+ * @brief Deserialize properties in the SUBACK packet received from the server.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts properties.
+ *
+ * @param[out] pPropBuffer Pointer to the property buffer.
+ * @param[in] pIndex Pointer to the start of the properties.
+ * @param[out] pSubackPropertyLength Pointer to the length of suback properties
+ * @param[in] remainingLength Remaining length of the incoming packet.
+ *
+ * @return #MQTTSuccess if SUBACK is valid;
+ * #MQTTBadResponse if SUBACK is invalid.
+ *
+ */
+static MQTTStatus_t deserializeSubUnsubAckProperties( MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ size_t * pSubackPropertyLength,
+ uint32_t remainingLength );
/**
- * @brief Deserialize an UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP packet.
+ * @brief Deserialize an PUBACK, PUBREC, PUBREL, or PUBCOMP packet.
*
* Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
- * the packet identifier.
+ * the packet identifier, reason code, properties.
*
* @param[in] pAck Pointer to the MQTT packet structure representing the packet.
* @param[out] pPacketIdentifier Packet ID of the ack type packet.
+ * @param[out] pReasonCode Structure to store reason code of the ack type packet.
+ * @param[in] requestProblem To validate the packet.
+ * @param[out] pPropBuffer Pointer to the property buffer.
*
- * @return #MQTTSuccess if UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP is valid;
- * #MQTTBadResponse if the packet doesn't follow the MQTT spec.
+ * @return #MQTTSuccess, #MQTTBadResponse, #MQTTBadParameter.
*/
-static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
- uint16_t * pPacketIdentifier );
+static MQTTStatus_t deserializePubAcks( const MQTTPacketInfo_t * pAck,
+ uint16_t * pPacketIdentifier,
+ MQTTReasonCodeInfo_t * pReasonCode,
+ bool requestProblem,
+ MQTTPropBuilder_t * pPropBuffer );
/**
- * @brief Deserialize a PINGRESP packet.
+ * @brief Validate the length and decode the publish ack properties.
*
- * Converts the packet from a stream of bytes to an #MQTTStatus_t.
+ * @param[out] pPropBuffer To store the decoded property.
+ * @param[in] pIndex Pointer to the current index of the buffer.
+ * @param[in] remainingLength Remaining length of properties in the incoming packet.
*
- * @param[in] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.
*
- * @return #MQTTSuccess if PINGRESP is valid; #MQTTBadResponse if the PINGRESP
- * packet doesn't follow MQTT spec.
+ * @return #MQTTSuccess, #MQTTBadResponse.
+ **/
+static MQTTStatus_t decodePubAckProperties( MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ uint32_t remainingLength );
+
+/**
+ * @brief Prints the appropriate message for the PUBREL, PUBACK response code if logs
+ * are enabled.
+ *
+ * @param[in] reasonCode MQTT Verion 5 standard PUBREL, PUBACK response code.
+ * @param[in] packetIdentifier Packet id of the ack packet.
+ *
+ * @return #MQTTSuccess, #MQTTServerRefused and #MQTTBadResponse.
*/
-static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp );
+static MQTTStatus_t logAckResponse( MQTTSuccessFailReasonCode_t reasonCode,
+ uint16_t packetIdentifier );
+
+/**
+ * @brief Deserialize properties in the PUBLISH packet received from the server.
+ *
+ * Converts the packet from a stream of bytes to an #MQTTPublishInfo_t and
+ * extracts properties.
+ *
+ * @param[out] pPublishInfo Pointer to #MQTTPublishInfo_t where output is
+ * written.
+ * @param[out] pPropBuffer Pointer to the property buffer.
+ * @param[in] pIndex Pointer to the start of the properties.
+ * @param[in] topicAliasMax Maximum allowed Topic Alias.
+ * @param[in] remainingLength Remaining length of the incoming packet.
+ *
+ * @return #MQTTSuccess if PUBLISH is valid; #MQTTBadResponse
+ * if the PUBLISH packet doesn't follow MQTT spec.
+ */
+static MQTTStatus_t deserializePublishProperties( MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ uint16_t topicAliasMax,
+ uint32_t remainingLength );
+
+/**
+ * @brief Prints and validates the appropriate message for the Disconnect response code if logs
+ * are enabled.
+ *
+ * @param[in] reasonCode MQTT Verion 5 standard DISCONNECT response code.
+ * @param[in] incoming To differentiate between outgoing and incoming disconnect.
+ *
+ * @return #MQTTSuccess, #MQTTBadParameter and #MQTTBadResponse.
+ */
+static MQTTStatus_t validateDisconnectResponse( MQTTSuccessFailReasonCode_t reasonCode,
+ bool incoming );
+
+/**
+ * @brief Validates the reason codes for the given ACK packet type.
+ *
+ * @param[in] ackPacketType ACK packet type for which the reason code is being added.
+ * @param[in] reasonCode The reason code being added to the ACK packet type.
+ *
+ * @return #MQTTSuccess or #MQTTBadParameter.
+ */
+static MQTTStatus_t validateReasonCodeForAck( uint8_t ackPacketType,
+ MQTTSuccessFailReasonCode_t reasonCode );
+
+/**
+ * @brief Returns the packet size of an ACK packet including the reason code.
+ *
+ * @param[in] pAckProperties Non-NULL properties to be added to the ack packet.
+ *
+ * @return The length of the ACK packet.
+ */
+static uint32_t getAckPacketSize( const MQTTPropBuilder_t * pAckProperties );
+
+/**
+ * @brief Validate if a reason code is valid for CONNACK packets.
+ *
+ * This function checks if the provided reason code is a valid CONNACK
+ * reason code according to the MQTT v5 specification.
+ *
+ * @param[in] reasonCode The reason code to validate.
+ *
+ * @return #MQTTSuccess if the reason code is valid for CONNACK;
+ * #MQTTServerRefused if the reason code indicates server refusal;
+ * #MQTTBadResponse if the reason code is invalid.
+ */
+static inline MQTTStatus_t isValidConnackReasonCode( uint8_t reasonCode );
+
+/**
+ * @brief Validate properties in the DISCONNECT packet received from the server.
+ *
+ * @note Incoming properties are different than the ones the client can send.
+ *
+ * @param[in] pIndex Pointer to the start of the properties.
+ * @param[in] disconnectPropertyLength Length of the properties in the DISCONNECT packet.
+ *
+ * @return #MQTTSuccess if DISCONNECT is valid;
+ * #MQTTBadResponse if the DISCONNECT packet is invalid.
+ */
+static MQTTStatus_t validateIncomingDisconnectProperties( uint8_t * pIndex,
+ uint32_t disconnectPropertyLength );
+
+/*-----------------------------------------------------------*/
+
+static uint32_t getAckPacketSize( const MQTTPropBuilder_t * pAckProperties )
+{
+ uint32_t packetSize = 0;
+
+ assert( pAckProperties != NULL );
+ assert( !CHECK_SIZE_T_OVERFLOWS_32BIT( pAckProperties->currentIndex ) );
+ assert( pAckProperties->currentIndex < MQTT_REMAINING_LENGTH_INVALID );
+
+ /* We do not need to check for overflow here as even if current index
+ * is close to or equal MQTT maximum remaining length, packetSize can
+ * accommodate it.
+ * Reason code 1
+ * Max encoded size (props) + 4
+ * Max encoded size (packet size) + 4
+ * Packet header + 1
+ * Packet ID + 2 = 12
+ */
+
+
+ /* 1 byte for reason code. */
+ packetSize += 1U;
+
+ /* Space taken to encode the property length and the properties themselves. */
+ packetSize += variableLengthEncodedSize( pAckProperties->currentIndex );
+ packetSize += pAckProperties->currentIndex;
+
+ /* Space taken to encode the remaining length. */
+ packetSize += variableLengthEncodedSize( packetSize );
+
+ /* ACK packet header 1 byte
+ * Packet ID + 2 bytes */
+ packetSize += 3U;
+
+ return packetSize;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateReasonCodeForAck( uint8_t ackPacketType,
+ MQTTSuccessFailReasonCode_t reasonCode )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ switch( ackPacketType )
+ {
+ case MQTT_PACKET_TYPE_PUBACK:
+
+ if( ( reasonCode != MQTT_REASON_PUBACK_SUCCESS ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_UNSPECIFIED_ERROR ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_NOT_AUTHORIZED ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_TOPIC_NAME_INVALID ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_QUOTA_EXCEEDED ) &&
+ ( reasonCode != MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID ) )
+ {
+ LogError( ( "Invalid reason code for PUBACK." ) );
+ status = MQTTBadParameter;
+ }
+
+ break;
+
+ case MQTT_PACKET_TYPE_PUBREC:
+
+ if( ( reasonCode != MQTT_REASON_PUBREC_SUCCESS ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_NO_MATCHING_SUBSCRIBERS ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_UNSPECIFIED_ERROR ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_IMPLEMENTATION_SPECIFIC_ERROR ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_NOT_AUTHORIZED ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_TOPIC_NAME_INVALID ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_PACKET_IDENTIFIER_IN_USE ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_QUOTA_EXCEEDED ) &&
+ ( reasonCode != MQTT_REASON_PUBREC_PAYLOAD_FORMAT_INVALID ) )
+ {
+ LogError( ( "Invalid reason code for PUBREC." ) );
+ status = MQTTBadParameter;
+ }
+
+ break;
+
+ case MQTT_PACKET_TYPE_PUBREL:
+
+ if( ( reasonCode != MQTT_REASON_PUBREL_SUCCESS ) &&
+ ( reasonCode != MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND ) )
+ {
+ LogError( ( "Invalid reason code for PUBREL." ) );
+ status = MQTTBadParameter;
+ }
+
+ break;
+
+ case MQTT_PACKET_TYPE_PUBCOMP:
+
+ if( ( reasonCode != MQTT_REASON_PUBCOMP_SUCCESS ) &&
+ ( reasonCode != MQTT_REASON_PUBCOMP_PACKET_IDENTIFIER_NOT_FOUND ) )
+ {
+ LogError( ( "Invalid reason code for PUBCOMP." ) );
+ status = MQTTBadParameter;
+ }
+
+ break;
+
+ default:
+ LogError( ( "Unknown ACK packet type: %" PRIu8 ".", ackPacketType ) );
+ status = MQTTBadParameter;
+ break;
+ }
+
+ return status;
+}
/*-----------------------------------------------------------*/
-static size_t remainingLengthEncodedSize( size_t length )
+static size_t remainingLengthEncodedSize( uint32_t length )
{
size_t encodedSize;
/* Determine how many bytes are needed to encode length.
- * The values below are taken from the MQTT 3.1.1 spec. */
+ * The values below are taken from the MQTT 5.0 spec. */
/* 1 byte is needed to encode lengths between 0 and 127. */
if( length < 128U )
@@ -490,81 +687,20 @@ static size_t remainingLengthEncodedSize( size_t length )
/*-----------------------------------------------------------*/
-static uint8_t * encodeRemainingLength( uint8_t * pDestination,
- size_t length )
-{
- uint8_t lengthByte;
- uint8_t * pLengthEnd = NULL;
- size_t remainingLength = length;
-
- assert( pDestination != NULL );
-
- pLengthEnd = pDestination;
-
- /* This algorithm is copied from the MQTT v3.1.1 spec. */
- do
- {
- lengthByte = ( uint8_t ) ( remainingLength % 128U );
- remainingLength = remainingLength / 128U;
-
- /* Set the high bit of this byte, indicating that there's more data. */
- if( remainingLength > 0U )
- {
- UINT8_SET_BIT( lengthByte, 7 );
- }
-
- /* Output a single encoded byte. */
- *pLengthEnd = lengthByte;
- pLengthEnd++;
- } while( remainingLength > 0U );
-
- return pLengthEnd;
-}
-
-/*-----------------------------------------------------------*/
-
-static uint8_t * encodeString( uint8_t * pDestination,
- const char * pSource,
- uint16_t sourceLength )
-{
- uint8_t * pBuffer = NULL;
-
- assert( pDestination != NULL );
-
- pBuffer = pDestination;
-
- /* The first byte of a UTF-8 string is the high byte of the string length. */
- *pBuffer = UINT16_HIGH_BYTE( sourceLength );
- pBuffer++;
-
- /* The second byte of a UTF-8 string is the low byte of the string length. */
- *pBuffer = UINT16_LOW_BYTE( sourceLength );
- pBuffer++;
-
- /* Copy the string into pBuffer. */
- if( pSource != NULL )
- {
- ( void ) memcpy( ( void * ) pBuffer, ( const void * ) pSource, sourceLength );
- }
-
- /* Return the pointer to the end of the encoded string. */
- pBuffer = &pBuffer[ sourceLength ];
-
- return pBuffer;
-}
-
-/*-----------------------------------------------------------*/
-
-static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize )
+static MQTTStatus_t calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ uint32_t publishPropertyLength )
{
- bool status = true;
- size_t packetSize = 0, payloadLimit = 0;
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t packetSize = 0;
+ uint32_t propertyAndPayloadLimit = 0;
assert( pPublishInfo != NULL );
assert( pRemainingLength != NULL );
assert( pPacketSize != NULL );
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) );
/* The variable header of a PUBLISH packet always contains the topic name.
* The first 2 bytes of UTF-8 string contains length of the string.
@@ -578,50 +714,61 @@ static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
packetSize += sizeof( uint16_t );
}
- /* Calculate the maximum allowed size of the payload for the given parameters.
- * This calculation excludes the "Remaining length" encoding, whose size is not
- * yet known. */
- payloadLimit = MQTT_MAX_REMAINING_LENGTH - packetSize - 1U;
+ packetSize += variableLengthEncodedSize( publishPropertyLength );
- /* Ensure that the given payload fits within the calculated limit. */
- if( pPublishInfo->payloadLength > payloadLimit )
+ /* Calculate the maximum allowed size of the properties and payload combined for
+ * the given parameters. */
+ propertyAndPayloadLimit = MQTT_MAX_REMAINING_LENGTH - packetSize;
+
+ if( publishPropertyLength > propertyAndPayloadLimit )
{
- LogError( ( "PUBLISH payload length of %lu cannot exceed "
+ LogError( ( "PUBLISH properties length of %lu cannot exceed "
"%lu so as not to exceed the maximum "
- "remaining length of MQTT 3.1.1 packet( %lu ).",
- ( unsigned long ) pPublishInfo->payloadLength,
- ( unsigned long ) payloadLimit,
+ "remaining length of MQTT 5.0 packet( %lu ).",
+ ( unsigned long ) publishPropertyLength,
+ ( unsigned long ) propertyAndPayloadLimit,
MQTT_MAX_REMAINING_LENGTH ) );
- status = false;
+ status = MQTTBadParameter;
}
else
{
- /* Add the length of the PUBLISH payload. At this point, the "Remaining length"
- * has been calculated. */
- packetSize += pPublishInfo->payloadLength;
-
- /* Now that the "Remaining length" is known, recalculate the payload limit
- * based on the size of its encoding. */
- payloadLimit -= remainingLengthEncodedSize( packetSize );
+ packetSize += publishPropertyLength;
+ propertyAndPayloadLimit -= publishPropertyLength;
+ }
- /* Check that the given payload fits within the size allowed by MQTT spec. */
- if( pPublishInfo->payloadLength > payloadLimit )
+ if( status == MQTTSuccess )
+ {
+ if( pPublishInfo->payloadLength > propertyAndPayloadLimit )
{
- LogError( ( "PUBLISH payload length of %lu cannot exceed "
+ LogError( ( "PUBLISH properties and payload combined length of %lu cannot exceed "
"%lu so as not to exceed the maximum "
- "remaining length of MQTT 3.1.1 packet( %lu ).",
- ( unsigned long ) pPublishInfo->payloadLength,
- ( unsigned long ) payloadLimit,
+ "remaining length of MQTT 5.0 packet( %lu ).",
+ ( unsigned long ) ( pPublishInfo->payloadLength + publishPropertyLength ),
+ ( unsigned long ) ( propertyAndPayloadLimit + publishPropertyLength ),
MQTT_MAX_REMAINING_LENGTH ) );
- status = false;
+ status = MQTTBadParameter;
}
else
{
- /* Set the "Remaining length" output parameter and calculate the full
- * size of the PUBLISH packet. */
- *pRemainingLength = packetSize;
+ packetSize += pPublishInfo->payloadLength;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Set the "Remaining length" output parameter and calculate the full
+ * size of the PUBLISH packet. */
+ *pRemainingLength = packetSize;
- packetSize += 1U + remainingLengthEncodedSize( packetSize );
+ packetSize += 1U + variableLengthEncodedSize( packetSize );
+
+ if( packetSize > maxPacketSize )
+ {
+ LogError( ( "Packet size is greater than the allowed maximum packet size." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
*pPacketSize = packetSize;
}
}
@@ -629,13 +776,79 @@ static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
LogDebug( ( "PUBLISH packet remaining length=%lu and packet size=%lu.",
( unsigned long ) *pRemainingLength,
( unsigned long ) *pPacketSize ) );
+
return status;
}
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
- size_t remainingLength,
+static MQTTStatus_t deserializePubAcks( const MQTTPacketInfo_t * pAck,
+ uint16_t * pPacketIdentifier,
+ MQTTReasonCodeInfo_t * pReasonCode,
+ bool requestProblem,
+ MQTTPropBuilder_t * pPropBuffer )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pIndex;
+
+ assert( pAck != NULL );
+ assert( pPacketIdentifier != NULL );
+ assert( pReasonCode != NULL );
+ assert( pAck->pRemainingData != NULL );
+
+ pIndex = pAck->pRemainingData;
+
+ if( pAck->remainingLength < 2U )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ /* Extract the packet identifier (third and fourth bytes) from ACK. */
+ *pPacketIdentifier = UINT16_DECODE( pIndex );
+ pIndex = &pIndex[ 2 ];
+
+ LogDebug( ( "Packet identifier is %hu.",
+ ( unsigned short ) *pPacketIdentifier ) );
+
+ /* Packet identifier cannot be 0. */
+ if( *pPacketIdentifier == 0U )
+ {
+ LogError( ( "Packet identifier cannot be 0." ) );
+ status = MQTTBadResponse;
+ }
+ }
+
+ /* If reason code is success, server can choose to send the reason code or not. */
+ if( ( status == MQTTSuccess ) && ( pAck->remainingLength > 2U ) )
+ {
+ pReasonCode->reasonCode = pIndex;
+ pReasonCode->reasonCodeLength = 1U;
+ pIndex++;
+ }
+
+ if( ( status == MQTTSuccess ) && ( pAck->remainingLength > 3U ) )
+ {
+ /* Protocol error to send user property and reason string if client has set request problem to false. */
+ if( requestProblem == false )
+ {
+ LogError( ( "User property and reason string not expected in ACK packet when requestProblem is false." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ /* 3 bytes have been used up by the packet ID (2) and reason code (1). */
+ status = decodePubAckProperties( pPropBuffer, pIndex, pAck->remainingLength - 3U );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
+ uint32_t remainingLength,
uint8_t * pBuffer,
size_t * headerSize )
{
@@ -646,56 +859,79 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
/* The first byte of a PUBLISH packet contains the packet type and flags. */
uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
- /* Get the start address of the buffer. */
- pIndex = pBuffer;
-
- /* Length of serialized packet = First byte
- * + Length of encoded remaining length
- * + Encoded topic length. */
- headerLength = 1U + remainingLengthEncodedSize( remainingLength ) + 2U;
-
- if( pPublishInfo->qos == MQTTQoS1 )
+ if( pPublishInfo == NULL )
{
- LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
+ LogError( ( "pPublishInfo cannot be NULL." ) );
+ status = MQTTBadParameter;
}
- else if( pPublishInfo->qos == MQTTQoS2 )
+ else if( pBuffer == NULL )
{
- LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
+ LogError( ( "pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
}
- else
+ else if( remainingLength >= MQTT_REMAINING_LENGTH_INVALID )
{
- /* Empty else MISRA 15.7 */
+ LogError( ( "Remaining length must be less than 268435456." ) );
+ status = MQTTBadParameter;
}
-
- if( pPublishInfo->retain == true )
+ else if( headerSize == NULL )
{
- LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
+ LogError( ( "headerSize cannot be NULL." ) );
+ status = MQTTBadParameter;
}
-
- if( pPublishInfo->dup == true )
+ else
{
- LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
- }
+ if( pPublishInfo->qos == MQTTQoS1 )
+ {
+ LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
+ UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
+ }
+ else if( pPublishInfo->qos == MQTTQoS2 )
+ {
+ LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
+ UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
+ }
+ else
+ {
+ /* Empty else MISRA 15.7 */
+ }
- *pIndex = publishFlags;
- pIndex++;
+ if( pPublishInfo->retain == true )
+ {
+ LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
+ UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
+ }
- /* The "Remaining length" is encoded from the second byte. */
- pIndex = encodeRemainingLength( pIndex, remainingLength );
+ if( pPublishInfo->dup == true )
+ {
+ LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
+ UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
+ }
- /* The first byte of a UTF-8 string is the high byte of the string length. */
- *pIndex = UINT16_HIGH_BYTE( pPublishInfo->topicNameLength );
- pIndex++;
+ /* Get the start address of the buffer. */
+ pIndex = pBuffer;
- /* The second byte of a UTF-8 string is the low byte of the string length. */
- *pIndex = UINT16_LOW_BYTE( pPublishInfo->topicNameLength );
- pIndex++;
+ /* Length of serialized packet = First byte
+ * + Length of encoded remaining length
+ * + Encoded topic length. */
+ headerLength = 1U + remainingLengthEncodedSize( remainingLength ) + 2U;
+
+ *pIndex = publishFlags;
+ pIndex++;
- *headerSize = headerLength;
+ /* The "Remaining length" is encoded from the second byte. */
+ pIndex = encodeVariableLength( pIndex, remainingLength );
+
+ /* The first byte of a UTF-8 string is the high byte of the string length. */
+ *pIndex = UINT16_HIGH_BYTE( pPublishInfo->topicNameLength );
+ pIndex++;
+
+ /* The second byte of a UTF-8 string is the low byte of the string length. */
+ *pIndex = UINT16_LOW_BYTE( pPublishInfo->topicNameLength );
+ pIndex++;
+
+ *headerSize = headerLength;
+ }
return status;
}
@@ -703,13 +939,14 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
/*-----------------------------------------------------------*/
static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pPublishProperties,
+ uint32_t remainingLength,
uint16_t packetIdentifier,
const MQTTFixedBuffer_t * pFixedBuffer,
bool serializePayload )
{
uint8_t * pIndex = NULL;
-
+ size_t propertyLength = 0U;
/* The first byte of a PUBLISH packet contains the packet type and flags. */
uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
@@ -720,10 +957,17 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
assert( ( pPublishInfo->qos == MQTTQoS0 ) || ( packetIdentifier != 0U ) );
/* Duplicate flag should be set only for Qos 1 or Qos 2. */
assert( ( pPublishInfo->dup != true ) || ( pPublishInfo->qos != MQTTQoS0 ) );
+ /* The topic name length must fit in 16-bits. */
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) );
/* Get the start address of the buffer. */
pIndex = pFixedBuffer->pBuffer;
+ if( ( pPublishProperties != NULL ) && ( pPublishProperties->pBuffer != NULL ) )
+ {
+ propertyLength = pPublishProperties->currentIndex;
+ }
+
if( pPublishInfo->qos == MQTTQoS1 )
{
LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
@@ -736,7 +980,7 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
}
else
{
- /* Empty else MISRA 15.7 */
+ /* No need to set any bits in a QoS0 packet. */
}
if( pPublishInfo->retain == true )
@@ -755,7 +999,7 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
pIndex++;
/* The "Remaining length" is encoded from the second byte. */
- pIndex = encodeRemainingLength( pIndex, remainingLength );
+ pIndex = encodeVariableLength( pIndex, remainingLength );
/* The topic name is placed after the "Remaining length". */
pIndex = encodeString( pIndex,
@@ -772,7 +1016,16 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
pIndex = &pIndex[ 2U ];
}
- /* The payload is placed after the packet identifier.
+ /* Properties are added after packet identifier. */
+ pIndex = encodeVariableLength( pIndex, propertyLength );
+
+ if( propertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pPublishProperties->pBuffer, propertyLength );
+ pIndex = &pIndex[ propertyLength ];
+ }
+
+ /* The payload is placed after the properties.
* Payload is copied over only if required by the flag serializePayload.
* This will help reduce an unnecessary copy of the payload into the buffer.
*/
@@ -792,10 +1045,10 @@ static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
}
-static size_t getRemainingLength( TransportRecv_t recvFunc,
- NetworkContext_t * pNetworkContext )
+static uint32_t getRemainingLength( TransportRecv_t recvFunc,
+ NetworkContext_t * pNetworkContext )
{
- size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
+ uint32_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
uint8_t encodedByte = 0;
int32_t bytesReceived = 0;
@@ -848,14 +1101,14 @@ static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
const size_t * pIndex,
MQTTPacketInfo_t * pIncomingPacket )
{
- size_t remainingLength = 0;
+ uint32_t remainingLength = 0;
size_t multiplier = 1;
size_t bytesDecoded = 0;
size_t expectedSize = 0;
uint8_t encodedByte = 0;
MQTTStatus_t status = MQTTSuccess;
- /* This algorithm is copied from the MQTT v3.1.1 spec. */
+ /* This algorithm is copied from the MQTT v5.0 spec. */
do
{
if( multiplier > 2097152U ) /* 128 ^ 3 */
@@ -896,13 +1149,20 @@ static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
if( status == MQTTSuccess )
{
/* Check that the decoded remaining length conforms to the MQTT specification. */
- expectedSize = remainingLengthEncodedSize( remainingLength );
+ expectedSize = variableLengthEncodedSize( remainingLength );
if( bytesDecoded != expectedSize )
{
LogError( ( "Expected and actual length of decoded bytes do not match.\n" ) );
status = MQTTBadResponse;
}
+ else if( CHECK_U32T_OVERFLOWS_SIZE_T( remainingLength ) )
+ {
+ LogError( ( "Remaining length %" PRIu32
+ " will overflow when stored in pIncomingPacket->remainingLength "
+ "(type: size_t).", remainingLength ) );
+ status = MQTTBadResponse;
+ }
else
{
pIncomingPacket->remainingLength = remainingLength;
@@ -931,6 +1191,8 @@ static bool incomingPacketValid( uint8_t packetType )
case MQTT_PACKET_TYPE_SUBACK:
case MQTT_PACKET_TYPE_UNSUBACK:
case MQTT_PACKET_TYPE_PINGRESP:
+ case MQTT_PACKET_TYPE_DISCONNECT:
+ case MQTT_PACKET_TYPE_AUTH:
status = true;
break;
@@ -956,9 +1218,9 @@ static bool incomingPacketValid( uint8_t packetType )
/*-----------------------------------------------------------*/
-static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
+static MQTTStatus_t checkPublishRemainingLength( uint32_t remainingLength,
MQTTQoS_t qos,
- size_t qos0Minimum )
+ uint32_t qos0Minimum )
{
MQTTStatus_t status = MQTTSuccess;
@@ -1048,114 +1310,284 @@ static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
static void logConnackResponse( uint8_t responseCode )
{
- const char * const pConnackResponses[ 6 ] =
+ /* Log an error based on the CONNACK response code. */
+ switch( responseCode )
{
- "Connection accepted.", /* 0 */
- "Connection refused: unacceptable protocol version.", /* 1 */
- "Connection refused: identifier rejected.", /* 2 */
- "Connection refused: server unavailable", /* 3 */
- "Connection refused: bad user name or password.", /* 4 */
- "Connection refused: not authorized." /* 5 */
- };
+ case ( uint8_t ) MQTT_REASON_CONNACK_SUCCESS:
+ LogDebug( ( "Connection accepted." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_UNSPECIFIED_ERROR:
+ LogError( ( "Connection refused: Unspecified error" ) );
+ break;
- /* Avoid unused parameter warning when assert and logs are disabled. */
- ( void ) responseCode;
- ( void ) pConnackResponses;
+ case ( uint8_t ) MQTT_REASON_CONNACK_MALFORMED_PACKET:
+ LogError( ( "Connection refused: Malformed Packet." ) );
+ break;
- assert( responseCode <= 5U );
+ case ( uint8_t ) MQTT_REASON_CONNACK_PROTOCOL_ERROR:
+ LogError( ( "Connection refused: Protocol Error." ) );
+ break;
- if( responseCode == 0u )
- {
- /* Log at Debug level for a success CONNACK response. */
- LogDebug( ( "%s", pConnackResponses[ 0 ] ) );
+ case ( uint8_t ) MQTT_REASON_CONNACK_IMPLEMENTATION_SPECIFIC_ERROR:
+ LogError( ( "Connection refused: Implementation specific error." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_UNSUPPORTED_PROTOCOL_VERSION:
+ LogError( ( "Connection refused: Unsupported Protocol Version." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_CLIENT_IDENTIFIER_NOT_VALID:
+ LogError( ( "Connection refused: Client Identifier not valid." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_BAD_USER_NAME_OR_PASSWORD:
+ LogError( ( "Connection refused: Bad User Name or Password." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_NOT_AUTHORIZED:
+ LogError( ( "Connection refused: Not authorized." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_UNAVAILABLE:
+ LogError( ( "Connection refused: Server unavailable." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_BUSY:
+ LogError( ( "Connection refused: Server busy." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_BANNED:
+ LogError( ( "Connection refused: Banned." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_BAD_AUTHENTICATION_METHOD:
+ LogError( ( "Connection refused: Bad authentication method." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_TOPIC_NAME_INVALID:
+ LogError( ( "Connection refused: Topic Name invalid." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_PACKET_TOO_LARGE:
+ LogError( ( "Connection refused: Packet too large ." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_QUOTA_EXCEEDED:
+ LogError( ( "Connection refused: Quota exceeded." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_PAYLOAD_FORMAT_INVALID:
+ LogError( ( "Connection refused: Payload format invalid." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_RETAIN_NOT_SUPPORTED:
+ LogError( ( "Connection refused: Retain not supported." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_QOS_NOT_SUPPORTED:
+ LogError( ( "Connection refused: QoS not supported." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_USE_ANOTHER_SERVER:
+ LogError( ( "Connection refused: Use another server." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_MOVED:
+ LogError( ( "Connection refused: Server moved." ) );
+ break;
+
+ case ( uint8_t ) MQTT_REASON_CONNACK_CONNECTION_RATE_EXCEEDED:
+ LogError( ( "Connection refused: Connection rate exceeded." ) );
+ break;
+
+ /* This branch will never be reached as there the caller checks the value before-hand. */
+ default:
+ /* LCOV_EXCL_START */
+ LogError( ( "Invalid reason code received." ) );
+ assert( false );
+ break;
+ /* LCOV_EXCL_STOP */
}
- else
- {
- /* Log an error based on the CONNACK response code. */
- LogError( ( "%s", pConnackResponses[ responseCode ] ) );
+}
+
+/*-----------------------------------------------------------*/
+
+static inline MQTTStatus_t isValidConnackReasonCode( uint8_t reasonCode )
+{
+ MQTTStatus_t status;
+
+ switch( reasonCode )
+ {
+ case ( uint8_t ) MQTT_REASON_CONNACK_SUCCESS:
+ case ( uint8_t ) MQTT_REASON_CONNACK_UNSPECIFIED_ERROR:
+ case ( uint8_t ) MQTT_REASON_CONNACK_MALFORMED_PACKET:
+ case ( uint8_t ) MQTT_REASON_CONNACK_PROTOCOL_ERROR:
+ case ( uint8_t ) MQTT_REASON_CONNACK_IMPLEMENTATION_SPECIFIC_ERROR:
+ case ( uint8_t ) MQTT_REASON_CONNACK_UNSUPPORTED_PROTOCOL_VERSION:
+ case ( uint8_t ) MQTT_REASON_CONNACK_CLIENT_IDENTIFIER_NOT_VALID:
+ case ( uint8_t ) MQTT_REASON_CONNACK_BAD_USER_NAME_OR_PASSWORD:
+ case ( uint8_t ) MQTT_REASON_CONNACK_NOT_AUTHORIZED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_UNAVAILABLE:
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_BUSY:
+ case ( uint8_t ) MQTT_REASON_CONNACK_BANNED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_BAD_AUTHENTICATION_METHOD:
+ case ( uint8_t ) MQTT_REASON_CONNACK_TOPIC_NAME_INVALID:
+ case ( uint8_t ) MQTT_REASON_CONNACK_PACKET_TOO_LARGE:
+ case ( uint8_t ) MQTT_REASON_CONNACK_QUOTA_EXCEEDED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_PAYLOAD_FORMAT_INVALID:
+ case ( uint8_t ) MQTT_REASON_CONNACK_RETAIN_NOT_SUPPORTED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_QOS_NOT_SUPPORTED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_USE_ANOTHER_SERVER:
+ case ( uint8_t ) MQTT_REASON_CONNACK_SERVER_MOVED:
+ case ( uint8_t ) MQTT_REASON_CONNACK_CONNECTION_RATE_EXCEEDED:
+ status = MQTTSuccess;
+ break;
+
+ default:
+ LogError( ( "Invalid reason code received." ) );
+ status = MQTTBadResponse;
+ break;
}
+
+ return status;
}
/*-----------------------------------------------------------*/
-static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
- bool * pSessionPresent )
+static MQTTStatus_t validateConnackParams( const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent )
{
MQTTStatus_t status = MQTTSuccess;
- const uint8_t * pRemainingData = NULL;
+ const uint8_t * pRemainingData;
+ uint8_t reasonCode;
- assert( pConnack != NULL );
+ assert( pIncomingPacket != NULL );
assert( pSessionPresent != NULL );
- pRemainingData = pConnack->pRemainingData;
+ assert( pIncomingPacket->pRemainingData != NULL );
+ assert( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK );
- /* According to MQTT 3.1.1, the second byte of CONNACK must specify a
- * "Remaining length" of 2. */
- if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )
+ /* Remaining Length of the CONNACK cannot be less than 3.
+ * 1 byte for each of the following:
+ * - Connect Acknowledge Flags
+ * - Connect Reason Code
+ * - Properties (0x00) indicating no trailing properties. */
+ if( pIncomingPacket->remainingLength < MQTT_PACKET_CONNACK_MINIMUM_SIZE )
{
- LogError( ( "CONNACK does not have remaining length of %u.",
- ( unsigned int ) MQTT_PACKET_CONNACK_REMAINING_LENGTH ) );
+ LogError( ( "Incomplete Connack received" ) );
status = MQTTBadResponse;
}
- /* Check the reserved bits in CONNACK. The high 7 bits of the third byte
- * in CONNACK must be 0. */
- else if( ( pRemainingData[ 0 ] | 0x01U ) != 0x01U )
+ if( status == MQTTSuccess )
{
- LogError( ( "Reserved bits in CONNACK incorrect." ) );
+ pRemainingData = pIncomingPacket->pRemainingData;
+ reasonCode = pRemainingData[ 1 ];
- status = MQTTBadResponse;
- }
- else
- {
- /* Determine if the "Session Present" bit is set. This is the lowest bit of
- * the third byte in CONNACK. */
- if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
- == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
+ /* Reserved bits in CONNACK must be 0. */
+ if( ( pRemainingData[ 0 ] | 0x01U ) != 0x01U )
{
- LogDebug( ( "CONNACK session present bit set." ) );
- *pSessionPresent = true;
+ LogError( ( "Reserved bits in CONNACK not set to 0." ) );
- /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the
- * "Session Present" bit is set. */
- if( pRemainingData[ 1 ] != 0U )
- {
- LogError( ( "Session Present bit is set, but connect return code in CONNACK is %u (nonzero).",
- ( unsigned int ) pRemainingData[ 1 ] ) );
- status = MQTTBadResponse;
- }
+ status = MQTTBadResponse;
}
else
{
- LogDebug( ( "CONNACK session present bit not set." ) );
- *pSessionPresent = false;
+ /* Determine if the "Session Present" bit is set. This is the
+ * lowest bit of the first byte of variable header. */
+ if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ) ==
+ MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
+ {
+ LogDebug( ( "CONNACK session present bit set." ) );
+ *pSessionPresent = true;
+
+ /* MQTT 5 specifies that the fourth byte in CONNACK must be 0 if the
+ * "Session Present" bit is set. */
+ if( reasonCode != 0U )
+ {
+ LogError( ( "Session Present bit is set, but connect return code in CONNACK is %u (nonzero).",
+ ( unsigned int ) reasonCode ) );
+ status = MQTTBadResponse;
+ }
+ }
+ else
+ {
+ LogDebug( ( "CONNACK session present bit not set." ) );
+ *pSessionPresent = false;
+ }
}
}
if( status == MQTTSuccess )
{
- /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */
- if( pRemainingData[ 1 ] > 5U )
+ if( isValidConnackReasonCode( reasonCode ) != MQTTSuccess )
{
- LogError( ( "CONNACK response %u is invalid.",
- ( unsigned int ) pRemainingData[ 1 ] ) );
-
status = MQTTBadResponse;
}
else
{
- /* Print the appropriate message for the CONNACK response code if logs are
- * enabled. */
- logConnackResponse( pRemainingData[ 1 ] );
-
- /* A nonzero CONNACK response code means the connection was refused. */
- if( pRemainingData[ 1 ] > 0U )
+ if( reasonCode != MQTT_REASON_CONNACK_SUCCESS )
{
status = MQTTServerRefused;
}
+
+ logConnackResponse( reasonCode );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeConnack( MQTTConnectionProperties_t * pConnackProperties,
+ const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropBuffer )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pVariableHeader = NULL;
+ MQTTStatus_t statusCopy = MQTTSuccess;
+
+ /* Validate the arguments. */
+ status = validateConnackParams( pIncomingPacket, pSessionPresent );
+
+ if( status == MQTTServerRefused )
+ {
+ statusCopy = status;
+ }
+
+ if( ( status == MQTTSuccess ) || ( status == MQTTServerRefused ) )
+ {
+ pVariableHeader = pIncomingPacket->pRemainingData;
+
+ /* Skip over flags and reason code. */
+ pVariableHeader = &pVariableHeader[ 2U ];
+ status = decodeVariableLength( pVariableHeader, pIncomingPacket->remainingLength - 2U, &propertyLength );
+ }
+
+ /* Validate the packet size if max packet size is set. */
+ if( status == MQTTSuccess )
+ {
+ /* Validate the remaining length. */
+ if( ( pIncomingPacket->remainingLength ) != ( 2U + propertyLength + variableLengthEncodedSize( propertyLength ) ) )
+ {
+ LogError( ( "Invalid Remaining Length" ) );
+ status = MQTTBadResponse;
+ }
+ /* Deserialize the connack properties. */
+ else
+ {
+ status = deserializeConnackProperties( pConnackProperties, propertyLength, pVariableHeader, pPropBuffer );
}
}
+ if( status == MQTTSuccess )
+ {
+ status = statusCopy;
+ }
+
return status;
}
@@ -1163,57 +1595,69 @@ static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t subscribePropLen,
+ uint32_t maxPacketSize,
MQTTSubscriptionType_t subscriptionType )
{
+ uint32_t packetSize = 0U;
+ size_t i;
MQTTStatus_t status = MQTTSuccess;
- size_t i = 0, packetSize = 0;
assert( pSubscriptionList != NULL );
- assert( subscriptionCount != 0U );
assert( pRemainingLength != NULL );
assert( pPacketSize != NULL );
+ assert( subscriptionCount != 0U );
+ assert( subscribePropLen < MQTT_REMAINING_LENGTH_INVALID );
- /* The variable header of a subscription packet consists of a 2-byte packet
- * identifier. */
+ /* 2 byte packet id. */
packetSize += sizeof( uint16_t );
- /* Sum the lengths of all subscription topic filters; add 1 byte for each
- * subscription's QoS if type is MQTT_SUBSCRIBE. */
+ packetSize += subscribePropLen;
+ packetSize += variableLengthEncodedSize( subscribePropLen );
+
for( i = 0; i < subscriptionCount; i++ )
{
- /* Add the length of the topic filter. MQTT strings are prepended
- * with 2 byte string length field. Hence 2 bytes are added to size. */
- packetSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );
-
- /* Only SUBSCRIBE packets include the QoS. */
- if( subscriptionType == MQTT_SUBSCRIBE )
+ if( CHECK_SIZE_T_OVERFLOWS_16BIT( pSubscriptionList[ i ].topicFilterLength ) )
{
- packetSize += 1U;
+ LogError( ( "Topic filter length must be less than 65536. Length is %" PRIu32, ( uint32_t ) pSubscriptionList[ i ].topicFilterLength ) );
+ status = MQTTBadParameter;
}
-
- /* Validate each topic filter. */
- if( ( pSubscriptionList[ i ].topicFilterLength == 0U ) ||
- ( pSubscriptionList[ i ].pTopicFilter == NULL ) )
+ else if( ADDITION_WILL_OVERFLOW_U32( packetSize, sizeof( uint16_t ) ) ||
+ ADDITION_WILL_OVERFLOW_U32( packetSize + sizeof( uint16_t ), pSubscriptionList[ i ].topicFilterLength ) )
{
+ LogError( ( "packetSize will overflow if more subscriptions are added to it." ) );
status = MQTTBadParameter;
- LogError( ( "Subscription #%lu in %sSUBSCRIBE packet cannot be empty.",
- ( unsigned long ) i,
- ( subscriptionType == MQTT_SUBSCRIBE ) ? "" : "UN" ) );
- /* It is not necessary to break as an error status has already been set. */
+ }
+ else
+ {
+ packetSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );
+
+ if( packetSize >= MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "Packet size must be smaller than 268435456" ) );
+ status = MQTTBadParameter;
+ }
+ else if( subscriptionType == MQTT_TYPE_SUBSCRIBE )
+ {
+ packetSize += 1U;
+ }
+ }
+
+ if( status != MQTTSuccess )
+ {
+ break;
}
}
/* At this point, the "Remaining length" has been calculated. Return error
- * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,
- * set the output parameter.*/
- if( packetSize > MQTT_MAX_REMAINING_LENGTH )
+ * if the "Remaining length" exceeds what is allowed by MQTT 5. Otherwise,
+ * set the output parameter. */
+ if( ( status == MQTTSuccess ) && ( packetSize > MQTT_MAX_REMAINING_LENGTH ) )
{
- LogError( ( "Subscription packet length of %lu exceeds"
- "the MQTT 3.1.1 maximum packet length of %lu.",
- ( unsigned long ) packetSize,
- MQTT_MAX_REMAINING_LENGTH ) );
+ LogError( ( "Subscribe packet size %" PRIu32 " exceeds 268435456.",
+ packetSize ) );
status = MQTTBadParameter;
}
@@ -1221,118 +1665,173 @@ static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t *
{
*pRemainingLength = packetSize;
- /* Calculate the full size of the subscription packet by adding
- * number of bytes required to encode the "Remaining length" field
- * plus 1 byte for the "Packet type" field. */
- packetSize += 1U + remainingLengthEncodedSize( packetSize );
-
- /*Set the pPacketSize output parameter. */
+ /* This is the total packet size which is the sum of:
+ * Remaining Length +
+ * Bytes required to encode the remaining length +
+ * 1 byte MQTT header
+ */
+ packetSize += 1U + variableLengthEncodedSize( packetSize );
*pPacketSize = packetSize;
+
+ if( packetSize > maxPacketSize )
+ {
+ LogError( ( "Packet size is greater than the allowed maximum packet size." ) );
+ status = MQTTBadParameter;
+ }
}
- LogDebug( ( "Subscription packet remaining length=%lu and packet size=%lu.",
+ LogDebug( ( "%s packet remaining length=%lu and packet size=%lu.",
+ ( subscriptionType == MQTT_TYPE_SUBSCRIBE ) ? "SUBSCRIBE" : "UNSUBSCRIBE",
( unsigned long ) *pRemainingLength,
( unsigned long ) *pPacketSize ) );
-
return status;
}
/*-----------------------------------------------------------*/
static MQTTStatus_t readSubackStatus( size_t statusCount,
- const uint8_t * pStatusStart )
+ const uint8_t * pStatusStart,
+ MQTTReasonCodeInfo_t * pReasonCodes )
{
- MQTTStatus_t status = MQTTSuccess;
+ MQTTStatus_t status = MQTTServerRefused;
uint8_t subscriptionStatus = 0;
size_t i = 0;
assert( pStatusStart != NULL );
- /* Iterate through each status byte in the SUBACK packet. */
for( i = 0; i < statusCount; i++ )
{
- /* Read a single status byte in SUBACK. */
subscriptionStatus = pStatusStart[ i ];
- /* MQTT 3.1.1 defines the following values as status codes. */
switch( subscriptionStatus )
{
case 0x00:
case 0x01:
case 0x02:
-
- LogDebug( ( "Topic filter %lu accepted, max QoS %u.",
+ LogDebug( ( "Topic Filter %lu accepted, max QoS %u.",
( unsigned long ) i,
( unsigned int ) subscriptionStatus ) );
+ status = MQTTSuccess;
break;
case 0x80:
+ LogWarn( ( "Topic Filter Refused." ) );
+ break;
- LogWarn( ( "Topic filter %lu refused.", ( unsigned long ) i ) );
+ case 0x83:
+ LogWarn( ( "Implementation specific error." ) );
+ break;
- /* Application should remove subscription from the list */
- status = MQTTServerRefused;
+ case 0x87:
+ LogWarn( ( "Not authorized." ) );
+ break;
+ case 0x8F:
+ LogWarn( ( "Topic Name Invalid." ) );
break;
- default:
- LogError( ( "Bad SUBSCRIBE status %u.",
- ( unsigned int ) subscriptionStatus ) );
+ case 0x91:
+ LogWarn( ( "Packet Identifier In Use." ) );
+ break;
- status = MQTTBadResponse;
+ case 0x97:
+ LogWarn( ( "Quota Exceeded." ) );
+ break;
+ case 0x9E:
+ LogWarn( ( "Shared Subscriptions Not Supported." ) );
break;
- }
- /* Stop parsing the subscription statuses if a bad response was received. */
- if( status == MQTTBadResponse )
- {
- break;
- }
- }
+ case 0xA1:
+ LogWarn( ( "Subscription Identifiers Not Supported." ) );
+ break;
+
+ case 0xA2:
+ LogWarn( ( "Wildcard Subscriptions Not Supported." ) );
+ break;
+
+ default:
+ LogError( ( "Bad Subscribe status %u.",
+ ( unsigned int ) subscriptionStatus ) );
+ status = MQTTBadResponse;
+ break;
+ }
+
+ if( status == MQTTBadResponse )
+ {
+ break;
+ }
+ }
+
+ if( ( status == MQTTSuccess ) || ( status == MQTTServerRefused ) )
+ {
+ pReasonCodes->reasonCode = pStatusStart;
+ pReasonCodes->reasonCodeLength = statusCount;
+ }
return status;
}
/*-----------------------------------------------------------*/
-static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
- uint16_t * pPacketIdentifier )
+static MQTTStatus_t deserializeSubUnsubAck( const MQTTPacketInfo_t * incomingPacket,
+ uint16_t * pPacketId,
+ MQTTReasonCodeInfo_t * pReasonCodes,
+ MQTTPropBuilder_t * pPropBuffer )
{
MQTTStatus_t status = MQTTSuccess;
- size_t remainingLength;
- const uint8_t * pVariableHeader = NULL;
+ uint8_t * pIndex = NULL;
+ uint32_t remainingLength = 0U;
+ size_t statusTotalBytes = 0U;
+ const uint8_t * pStatusStart;
+ size_t propertyLength = 0U;
- assert( pSuback != NULL );
- assert( pPacketIdentifier != NULL );
+ /* Validate input parameters using assert. */
+ assert( incomingPacket != NULL );
+ assert( pPacketId != NULL );
+ assert( pReasonCodes != NULL );
- remainingLength = pSuback->remainingLength;
- pVariableHeader = pSuback->pRemainingData;
+ pIndex = incomingPacket->pRemainingData;
+ remainingLength = incomingPacket->remainingLength;
- /* A SUBACK must have a remaining length of at least 3 to accommodate the
- * packet identifier and at least 1 return code. */
- if( remainingLength < 3U )
+ if( incomingPacket->remainingLength < 4U )
{
- LogError( ( "SUBACK cannot have a remaining length less than 3." ) );
+ LogError( ( "Suback Packet Cannot have a remaining Length of less than 4." ) );
status = MQTTBadResponse;
}
else
{
- /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */
- *pPacketIdentifier = UINT16_DECODE( pVariableHeader );
-
- LogDebug( ( "Packet identifier %hu.",
- ( unsigned short ) *pPacketIdentifier ) );
+ *pPacketId = UINT16_DECODE( pIndex );
+ pIndex = &pIndex[ 2 ];
+ LogDebug( ( "Packet Identifier is %hu.",
+ ( unsigned short ) *pPacketId ) );
- if( *pPacketIdentifier == 0U )
+ if( *pPacketId == 0U )
{
+ LogError( ( "Packet Id cannot be 0" ) );
status = MQTTBadResponse;
}
- else
- {
- status = readSubackStatus( remainingLength - sizeof( uint16_t ),
- &pVariableHeader[ sizeof( uint16_t ) ] );
- }
+ }
+
+ if( ( status == MQTTSuccess ) && ( incomingPacket->remainingLength > 4U ) )
+ {
+ status = deserializeSubUnsubAckProperties( pPropBuffer,
+ pIndex,
+ &propertyLength,
+ incomingPacket->remainingLength );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Total number of bytes used by the properties - the encoded length + the actual properties. */
+ size_t totalPropertiesLength = propertyLength + variableLengthEncodedSize( propertyLength );
+
+ /* Total bytes of status codes = length - packet ID - properties total length. */
+ statusTotalBytes = remainingLength - sizeof( uint16_t ) - totalPropertiesLength;
+
+ /* Status codes start just after the properties. */
+ pStatusStart = &pIndex[ totalPropertiesLength ];
+ status = readSubackStatus( statusTotalBytes, pStatusStart, pReasonCodes );
}
return status;
@@ -1343,7 +1842,7 @@ static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
MQTTStatus_t status = MQTTSuccess;
@@ -1390,6 +1889,22 @@ static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo
( unsigned long ) packetSize ) );
status = MQTTNoMemory;
}
+
+ if( status == MQTTSuccess )
+ {
+ size_t it;
+
+ for( it = 0; it < subscriptionCount; it++ )
+ {
+ /* Check whether the topic filter and the topic filter length are non-zero. */
+ if( ( pSubscriptionList[ it ].pTopicFilter == NULL ) || ( pSubscriptionList[ it ].topicFilterLength == 0 ) )
+ {
+ LogError( ( "Topic filter length must be non-zero and the topic filter must be non-NULL." ) );
+ status = MQTTBadParameter;
+ break;
+ }
+ }
+ }
}
return status;
@@ -1399,55 +1914,63 @@ static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo
static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- MQTTPublishInfo_t * pPublishInfo )
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * pPropBuffer,
+ uint16_t topicAliasMax )
{
MQTTStatus_t status = MQTTSuccess;
- const uint8_t * pVariableHeader, * pPacketIdentifierHigh = NULL;
+ const uint8_t * pPacketIdentifierHigh = NULL;
+ uint8_t * pIndex = NULL;
assert( pIncomingPacket != NULL );
+ assert( pIncomingPacket->pRemainingData != NULL );
assert( pPacketId != NULL );
assert( pPublishInfo != NULL );
- assert( pIncomingPacket->pRemainingData != NULL );
- pVariableHeader = pIncomingPacket->pRemainingData;
+ pIndex = pIncomingPacket->pRemainingData;
/* The flags are the lower 4 bits of the first byte in PUBLISH. */
status = processPublishFlags( ( pIncomingPacket->type & 0x0FU ), pPublishInfo );
if( status == MQTTSuccess )
{
/* Sanity checks for "Remaining length". A QoS 0 PUBLISH must have a remaining
- * length of at least 3 to accommodate topic name length (2 bytes) and topic
- * name (at least 1 byte). A QoS 1 or 2 PUBLISH must have a remaining length of
- * at least 5 for the packet identifier in addition to the topic name length and
- * topic name. */
+ * length of at least 4 to accommodate topic name length (2 bytes), topic name
+ * (at least 1 byte) and, Property Length (at least 1 byte for 0 properties).
+ * A QoS 1 or 2 PUBLISH must have a remaining length of at least 5 for the packet
+ * identifier in addition to the topic name length and topic name. */
status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
pPublishInfo->qos,
- MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0 );
+ 4U );
}
if( status == MQTTSuccess )
{
/* Extract the topic name starting from the first byte of the variable header.
* The topic name string starts at byte 3 in the variable header. */
- pPublishInfo->topicNameLength = UINT16_DECODE( pVariableHeader );
+ pPublishInfo->topicNameLength = UINT16_DECODE( pIndex );
+ pIndex = &pIndex[ sizeof( uint16_t ) ];
/* Sanity checks for topic name length and "Remaining length". The remaining
- * length must be at least as large as the variable length header. */
+ * length must be at least as large as the variable length header:
+ * 2 bytes to encode the Topic Length +
+ * length of the topic string +
+ * 1 byte for the property length (when 0 properties).
+ */
status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
pPublishInfo->qos,
- pPublishInfo->topicNameLength + sizeof( uint16_t ) );
+ sizeof( uint16_t ) + pPublishInfo->topicNameLength + sizeof( uint8_t ) );
}
if( status == MQTTSuccess )
{
/* Parse the topic. */
- pPublishInfo->pTopicName = ( const char * ) ( &pVariableHeader[ sizeof( uint16_t ) ] );
- LogDebug( ( "Topic name length: %hu.", ( unsigned short ) pPublishInfo->topicNameLength ) );
+ pPublishInfo->pTopicName = ( char * ) pIndex;
+ LogDebug( ( "Topic name: %hu.", ( unsigned short ) pPublishInfo->topicNameLength ) );
/* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet
* identifier starts immediately after the topic name. */
- /* coverity[tainted_scalar] */
pPacketIdentifierHigh = ( const uint8_t * ) ( &pPublishInfo->pTopicName[ pPublishInfo->topicNameLength ] );
+ pIndex = &pIndex[ pPublishInfo->topicNameLength ];
if( pPublishInfo->qos > MQTTQoS0 )
{
@@ -1456,23 +1979,36 @@ static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket
LogDebug( ( "Packet identifier %hu.",
( unsigned short ) *pPacketId ) );
- /* Advance pointer two bytes to start of payload as in the QoS 0 case. */
- pPacketIdentifierHigh = &pPacketIdentifierHigh[ sizeof( uint16_t ) ];
-
/* Packet identifier cannot be 0. */
if( *pPacketId == 0U )
{
LogError( ( "Packet identifier cannot be 0." ) );
status = MQTTBadResponse;
}
+
+ if( status == MQTTSuccess )
+ {
+ pIndex = &pIndex[ sizeof( uint16_t ) ];
+ }
}
}
if( status == MQTTSuccess )
{
+ status = deserializePublishProperties( pPublishInfo, pPropBuffer, pIndex,
+ topicAliasMax, pIncomingPacket->remainingLength );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ pIndex = &pIndex[ variableLengthEncodedSize( pPublishInfo->propertyLength ) ];
+ pIndex = &pIndex[ pPublishInfo->propertyLength ];
+
/* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain
* a packet identifier, but QoS 0 PUBLISH packets do not. */
- pPublishInfo->payloadLength = pIncomingPacket->remainingLength - pPublishInfo->topicNameLength - sizeof( uint16_t );
+ pPublishInfo->payloadLength = pIncomingPacket->remainingLength - pPublishInfo->topicNameLength -
+ sizeof( uint16_t ) - pPublishInfo->propertyLength -
+ variableLengthEncodedSize( pPublishInfo->propertyLength );
if( pPublishInfo->qos != MQTTQoS0 )
{
@@ -1481,7 +2017,8 @@ static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket
}
/* Set payload if it exists. */
- pPublishInfo->pPayload = ( pPublishInfo->payloadLength != 0U ) ? pPacketIdentifierHigh : NULL;
+
+ pPublishInfo->pPayload = ( pPublishInfo->payloadLength != 0U ) ? pIndex : NULL;
LogDebug( ( "Payload length %lu.",
( unsigned long ) pPublishInfo->payloadLength ) );
@@ -1492,35 +2029,429 @@ static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket
/*-----------------------------------------------------------*/
-static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
- uint16_t * pPacketIdentifier )
+static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp )
{
MQTTStatus_t status = MQTTSuccess;
- assert( pAck != NULL );
- assert( pPacketIdentifier != NULL );
+ assert( pPingresp != NULL );
- /* Check that the "Remaining length" of the received ACK is 2. */
- if( pAck->remainingLength != MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH )
+ /* Check the "Remaining length" (second byte) of the received PINGRESP is 0. */
+ if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )
{
- LogError( ( "ACK does not have remaining length of %u.",
- ( unsigned int ) MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH ) );
+ LogError( ( "PINGRESP does not have remaining length of %u.",
+ MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) );
status = MQTTBadResponse;
}
- else
- {
- /* Extract the packet identifier (third and fourth bytes) from ACK. */
- *pPacketIdentifier = UINT16_DECODE( pAck->pRemainingData );
- LogDebug( ( "Packet identifier %hu.",
- ( unsigned short ) *pPacketIdentifier ) );
+ return status;
+}
- /* Packet identifier cannot be 0. */
- if( *pPacketIdentifier == 0U )
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeConnackProperties( MQTTConnectionProperties_t * pConnackProperties,
+ uint32_t length,
+ uint8_t * pIndex,
+ MQTTPropBuilder_t * pPropBuffer )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pVariableHeader = pIndex;
+ uint32_t propertyLength = length;
+ bool sessionExpiry = false;
+ bool serverReceiveMax = false;
+ bool maxQos = false;
+ bool retain = false;
+ bool maxPacket = false;
+ bool clientId = false;
+ bool topicAlias = false;
+ bool wildcard = false;
+ bool subId = false;
+ bool sharedsub = false;
+ bool keepAlive = false;
+ bool responseInfo = false;
+ bool serverReference = false;
+ bool authMethod = false;
+ bool authData = false;
+ bool reasonString = false;
+
+ pVariableHeader = &pVariableHeader[ variableLengthEncodedSize( propertyLength ) ];
+
+ if( pPropBuffer != NULL )
+ {
+ pPropBuffer->pBuffer = pVariableHeader;
+ pPropBuffer->bufferLength = propertyLength;
+ pPropBuffer->currentIndex = propertyLength;
+ pPropBuffer->fieldSet = 0U;
+ }
+
+ /* Decode all the properties received, validate and store them in pConnackProperties. */
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pVariableHeader;
+ const char * data;
+ size_t dataLength;
+
+ pVariableHeader = &pVariableHeader[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
{
- LogError( ( "Packet identifier cannot be 0." ) );
- status = MQTTBadResponse;
+ /* In absence of this property, the value in the connect packet is used. */
+ case MQTT_SESSION_EXPIRY_ID:
+ status = decodeUint32t( &pConnackProperties->sessionExpiry, &propertyLength,
+ &sessionExpiry, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Session expiry from server: %" PRIu32, pConnackProperties->sessionExpiry ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_RECEIVE_MAX_ID:
+ status = decodeUint16t( &pConnackProperties->serverReceiveMax, &propertyLength,
+ &serverReceiveMax, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Receive max cannot be 0. */
+ if( pConnackProperties->serverReceiveMax == 0U )
+ {
+ LogError( ( "Receive Maximum value set to 0 by the server." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Server receive maximum: %" PRIu16, pConnackProperties->serverReceiveMax ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_RECEIVE_MAXIMUM_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_MAX_QOS_ID:
+ status = decodeUint8t( &pConnackProperties->serverMaxQos, &propertyLength,
+ &maxQos, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be anything else except 0 or 1. */
+ if( pConnackProperties->serverMaxQos > 1U )
+ {
+ LogError( ( "Invalid maximum QoS value set to %" PRIu8 " (not 0 or 1) by the server.",
+ pConnackProperties->serverMaxQos ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Server maximum QoS: %" PRIu8, pConnackProperties->serverMaxQos ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_MAX_QOS_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_RETAIN_AVAILABLE_ID:
+ status = decodeUint8t( &pConnackProperties->retainAvailable, &propertyLength,
+ &retain, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be anything else except 0 or 1. */
+ if( pConnackProperties->retainAvailable > 1U )
+ {
+ LogError( ( "Invalid retain available value set by the server %" PRIu8 " (not 0 or 1)",
+ pConnackProperties->retainAvailable ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Retain available: %" PRIu8, pConnackProperties->retainAvailable ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_RETAIN_AVAILABLE_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_MAX_PACKET_SIZE_ID:
+ status = decodeUint32t( &pConnackProperties->serverMaxPacketSize, &propertyLength,
+ &maxPacket, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be 0. */
+ if( pConnackProperties->serverMaxPacketSize == 0U )
+ {
+ LogError( ( "Server set maximum packet size to 0. Invalid response." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Server maximum packet size: %" PRIu32, pConnackProperties->serverMaxPacketSize ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_MAX_PACKET_SIZE_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_ASSIGNED_CLIENT_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &clientId, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Assigned client ID: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_ASSIGNED_CLIENT_ID_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+ status = decodeUint16t( &pConnackProperties->serverTopicAliasMax, &propertyLength,
+ &topicAlias, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Topic alias max ID: %" PRIu16, pConnackProperties->serverTopicAliasMax ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_TOPIC_ALIAS_MAX_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_REASON_STRING_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &reasonString, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Proper uses for the reason string in the Client would include using this information
+ * in an exception thrown by the Client code, or writing this string to a log. */
+ LogInfo( ( "Reason string from server: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_REASON_STRING_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key, &keyLength, &value, &valueLength, &propertyLength, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "User property: %.*s : %.*s", ( int ) keyLength, key, ( int ) valueLength, value ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_USER_PROP_POS );
+ }
+ }
+ }
+ break;
+
+ case MQTT_WILDCARD_ID:
+ status = decodeUint8t( &pConnackProperties->isWildcardAvailable, &propertyLength,
+ &wildcard, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be anything except 0 or 1. */
+ if( pConnackProperties->isWildcardAvailable > 1U )
+ {
+ LogError( ( "Server set wildcard value to %u (not 0 or 1). Invalid response.",
+ pConnackProperties->isWildcardAvailable ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Wildcard subscription available: %s", pConnackProperties->isWildcardAvailable ? "Yes" : "No" ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_WILDCARD_SUBSCRIPTION_AVAILABLE_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_SUB_AVAILABLE_ID:
+ status = decodeUint8t( &pConnackProperties->isSubscriptionIdAvailable, &propertyLength,
+ &subId, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be anything except 0 or 1. */
+ if( pConnackProperties->isSubscriptionIdAvailable > 1U )
+ {
+ LogError( ( "Server set subscription ID availability to %u (not 0 or 1). Invalid response.",
+ pConnackProperties->isSubscriptionIdAvailable ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Subscription ID available: %s", pConnackProperties->isSubscriptionIdAvailable ? "Yes" : "No" ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_SUBSCRIPTION_ID_AVAILABLE_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_SHARED_SUB_ID:
+ status = decodeUint8t( &pConnackProperties->isSharedAvailable, &propertyLength,
+ &sharedsub, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error for this value to be anything except 0 or 1. */
+ if( pConnackProperties->isSharedAvailable > 1U )
+ {
+ LogError( ( "Server set shared sub availability to %u (not 0 or 1). Invalid response.",
+ pConnackProperties->isSharedAvailable ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Shared subscription available: %s", pConnackProperties->isSharedAvailable ? "Yes" : "No" ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_SHARED_SUBSCRIPTION_AVAILABLE_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_SERVER_KEEP_ALIVE_ID:
+ status = decodeUint16t( &pConnackProperties->serverKeepAlive, &propertyLength,
+ &keepAlive, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Server keep alive: %d", ( int ) pConnackProperties->serverKeepAlive ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_SERVER_KEEP_ALIVE_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_RESPONSE_INFO_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &responseInfo, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ /* Protocol error to send response information if the client has not requested it. */
+ if( pConnackProperties->requestResponseInfo == false )
+ {
+ LogError( ( "Client did not request information still server sent it. Protocol error." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ LogDebug( ( "Response information: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_RESPONSE_INFORMATION_POS );
+ }
+ }
+ }
+
+ break;
+
+ case MQTT_SERVER_REF_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &serverReference, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Server reference: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_SERVER_REFERENCE_POS );
+ }
+ }
+
+ break;
+
+ case MQTT_AUTH_METHOD_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &authMethod, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Authentication method received: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_AUTHENTICATION_METHOD_POS );
+ }
+ }
+
+ /* TODO: AUTH method should be returned to the application to allow the
+ * authentication to complete. */
+ break;
+
+ case MQTT_AUTH_DATA_ID:
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &authData, &pVariableHeader );
+
+ if( status == MQTTSuccess )
+ {
+ LogDebug( ( "Auth data received: %.*s", ( int ) dataLength, data ) );
+
+ if( pPropBuffer != NULL )
+ {
+ UINT32_SET_BIT( pPropBuffer->fieldSet, MQTT_AUTHENTICATION_DATA_POS );
+ }
+ }
+
+ /* TODO: AUTH Data should be returned to the application to allow the
+ * authentication to complete. */
+ break;
+
+ /* Protocol error to include any other property id. */
+ default:
+ status = MQTTBadResponse;
+ break;
}
}
@@ -1529,121 +2460,192 @@ static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
/*-----------------------------------------------------------*/
-static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp )
+static MQTTStatus_t logAckResponse( MQTTSuccessFailReasonCode_t reasonCode,
+ uint16_t packetIdentifier )
{
MQTTStatus_t status = MQTTSuccess;
- assert( pPingresp != NULL );
-
- /* Check the "Remaining length" (second byte) of the received PINGRESP is 0. */
- if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )
+ switch( reasonCode )
{
- LogError( ( "PINGRESP does not have remaining length of %u.",
- MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) );
+ case MQTT_REASON_PUBACK_SUCCESS: /* Also equivalent to MQTT_REASON_PUBREL_SUCCESS. */
+ ( void ) packetIdentifier;
+ break;
- status = MQTTBadResponse;
- }
+ case MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS:
+ LogDebug( ( "Publish accepted with packet id %hu: No matching subscribers.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- return status;
-}
+ case MQTT_REASON_PUBACK_UNSPECIFIED_ERROR:
+ LogDebug( ( "Publish refused with packet id %hu: Connection rate exceeded.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
-uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex,
- const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength )
-{
- uint8_t * pIndexLocal = pIndex;
- uint8_t connectFlags = 0U;
+ case MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR:
+ LogDebug( ( "Publish refused with packet id %hu: The PUBLISH is valid but the receiver is not willing to accept it.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
+
+ case MQTT_REASON_PUBACK_NOT_AUTHORIZED:
+ LogDebug( ( "Publish refused with packet id %hu: The PUBLISH is not authorized.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- /* The first byte in the CONNECT packet is the control packet type. */
- *pIndexLocal = MQTT_PACKET_TYPE_CONNECT;
- pIndexLocal++;
+ case MQTT_REASON_PUBACK_TOPIC_NAME_INVALID:
+ LogDebug( ( "Publish refused with packet id %hu: Topic Name not accepted.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- /* The remaining length of the CONNECT packet is encoded starting from the
- * second byte. The remaining length does not include the length of the fixed
- * header or the encoding of the remaining length. */
- pIndexLocal = encodeRemainingLength( pIndexLocal, remainingLength );
+ case MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE:
+ LogDebug( ( "Publish refused with packet id %hu: The Packet Identifier is already in use. ",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable
- * header. This string is 4 bytes long. */
- pIndexLocal = encodeString( pIndexLocal, "MQTT", 4 );
+ case MQTT_REASON_PUBACK_QUOTA_EXCEEDED:
+ LogDebug( ( "Publish refused with packet id %hu: Quota exceeded.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- /* The MQTT protocol version is the second field of the variable header. */
- *pIndexLocal = MQTT_VERSION_3_1_1;
- pIndexLocal++;
+ case MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID:
+ LogDebug( ( "Publish refused with packet id %hu: Payload format indicator is invalid.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
- /* Set the clean session flag if needed. */
- if( pConnectInfo->cleanSession == true )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
+ case MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND:
+ LogError( ( "Publish refused with packet id %hu: Packet identifier invalid.",
+ ( unsigned short ) packetIdentifier ) );
+ break;
+
+ default:
+ status = MQTTBadResponse;
+ break;
}
- /* Set the flags for username and password if provided. */
- if( pConnectInfo->pUserName != NULL )
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t deserializeSubUnsubAckProperties( MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ size_t * pSubackPropertyLength,
+ uint32_t remainingLength )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pLocalIndex = pIndex;
+ const char * pReasonString;
+ size_t reasonStringLength;
+ bool reasonString = false;
+
+ status = decodeVariableLength( pLocalIndex, remainingLength - 2U, &propertyLength );
+ *pSubackPropertyLength = propertyLength;
+
+ if( status == MQTTSuccess )
{
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
+ pLocalIndex = &pLocalIndex[ variableLengthEncodedSize( propertyLength ) ];
}
- if( pConnectInfo->pPassword != NULL )
+ if( pPropBuffer != NULL )
{
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
+ pPropBuffer->bufferLength = propertyLength;
+ pPropBuffer->pBuffer = pLocalIndex;
}
- /* Set will flag if a Last Will and Testament is provided. */
- if( pWillInfo != NULL )
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
{
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
+ uint8_t propertyId = *pLocalIndex;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
- /* Flags only need to be changed for Will QoS 1 or 2. */
- if( pWillInfo->qos == MQTTQoS1 )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
- }
- else if( pWillInfo->qos == MQTTQoS2 )
+ switch( propertyId )
{
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
- }
- else
- {
- /* Empty else MISRA 15.7 */
- }
+ case MQTT_REASON_STRING_ID:
+ status = decodeUtf8( &pReasonString, &reasonStringLength, &propertyLength,
+ &reasonString, &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ if( pReasonString )
+ {
+ LogInfo( ( "SubAck reason string sent by server: %.*s",
+ ( int ) reasonStringLength, pReasonString ) );
+ }
+ }
- if( pWillInfo->retain == true )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
- }
- }
+ break;
- *pIndexLocal = connectFlags;
- pIndexLocal++;
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * propertyKey;
+ size_t propertyKeyLen;
+ const char * propertyValue;
+ size_t propertyValueLen;
+ status = decodeUserProp( &propertyKey, &propertyKeyLen, &propertyValue,
+ &propertyValueLen, &propertyLength, &pLocalIndex );
+ }
+ break;
- /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */
- pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );
- pIndexLocal[ 1 ] = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );
- pIndexLocal = &pIndexLocal[ 2 ];
+ default:
+ status = MQTTBadResponse;
+ break;
+ }
+ }
- return pIndexLocal;
+ return status;
}
+
/*-----------------------------------------------------------*/
static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
uint8_t * pIndex = NULL;
+ size_t connectPropertyLength = 0U;
+ size_t willPropertyLength = 0U;
assert( pConnectInfo != NULL );
assert( pFixedBuffer != NULL );
assert( pFixedBuffer->pBuffer != NULL );
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->clientIdentifierLength ) );
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->userNameLength ) );
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->passwordLength ) );
+
+ if( pWillInfo != NULL )
+ {
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pWillInfo->topicNameLength ) );
+ }
pIndex = pFixedBuffer->pBuffer;
/* Serialize the header. */
- pIndex = MQTT_SerializeConnectFixedHeader( pIndex,
- pConnectInfo,
- pWillInfo,
- remainingLength );
+ pIndex = serializeConnectFixedHeader( pIndex,
+ pConnectInfo,
+ pWillInfo,
+ remainingLength );
+
+ if( ( pConnectProperties != NULL ) && ( pConnectProperties->pBuffer != NULL ) )
+ {
+ connectPropertyLength = pConnectProperties->currentIndex;
+ }
+
+ if( ( pWillProperties != NULL ) && ( pWillProperties->pBuffer != NULL ) )
+ {
+ willPropertyLength = pWillProperties->currentIndex;
+ }
+
+ /* Write the properties length into the CONNECT packet. */
+ pIndex = encodeVariableLength( pIndex, connectPropertyLength );
+
+ if( connectPropertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pConnectProperties->pBuffer, connectPropertyLength );
+ pIndex = &pIndex[ connectPropertyLength ];
+ }
/* Write the client identifier into the CONNECT packet. */
pIndex = encodeString( pIndex,
@@ -1653,6 +2655,14 @@ static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
/* Write the will topic name and message into the CONNECT packet if provided. */
if( pWillInfo != NULL )
{
+ pIndex = encodeVariableLength( pIndex, willPropertyLength );
+
+ if( willPropertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pWillProperties->pBuffer, willPropertyLength );
+ pIndex = &pIndex[ willPropertyLength ];
+ }
+
pIndex = encodeString( pIndex,
pWillInfo->pTopicName,
pWillInfo->topicNameLength );
@@ -1684,59 +2694,410 @@ static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize )
+static MQTTStatus_t deserializePublishProperties( MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ uint16_t topicAliasMax,
+ uint32_t remainingLength )
{
MQTTStatus_t status = MQTTSuccess;
- size_t remainingLength;
+ uint32_t propertyLength = 0U;
+ uint8_t * pLocalIndex = pIndex;
+ uint32_t subscriptionId;
+ uint32_t remainingLengthForProperties;
+ bool contentType = false;
+ bool messageExpiryInterval = false;
+ bool responseTopic = false;
+ bool topicAlias = false;
+ bool payloadFormatIndicator = false;
+ bool correlationData = false;
+ uint16_t topicAliasVal;
+
+ assert( !CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) );
+
+ /* Decode Property Length. */
+ remainingLengthForProperties = remainingLength;
+ remainingLengthForProperties -= pPublishInfo->topicNameLength + sizeof( uint16_t );
+ remainingLengthForProperties -= ( pPublishInfo->qos > MQTTQoS0 ) ? sizeof( uint16_t ) : 0U;
+
+ status = decodeVariableLength( pLocalIndex, remainingLengthForProperties, &propertyLength );
+ pPublishInfo->propertyLength = propertyLength;
- /* The CONNECT packet will always include a 10-byte variable header. */
- size_t connectPacketSize = MQTT_PACKET_CONNECT_HEADER_SIZE;
-
- /* Validate arguments. */
- if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) ||
- ( pPacketSize == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
- "pRemainingLength=%p, pPacketSize=%p.",
- ( void * ) pConnectInfo,
- ( void * ) pRemainingLength,
- ( void * ) pPacketSize ) );
- status = MQTTBadParameter;
- }
- else if( ( pConnectInfo->clientIdentifierLength == 0U ) ^ ( ( pConnectInfo->pClientIdentifier == NULL ) || ( *( pConnectInfo->pClientIdentifier ) == '\0' ) ) )
+ if( status == MQTTSuccess )
{
- LogError( ( "Client ID length and value mismatch." ) );
- status = MQTTBadParameter;
+ status = checkPublishRemainingLength( remainingLength,
+ pPublishInfo->qos,
+ pPublishInfo->topicNameLength +
+ sizeof( uint16_t ) + propertyLength +
+ variableLengthEncodedSize( propertyLength ) );
}
- else if( ( pConnectInfo->clientIdentifierLength == 0U ) && ( pConnectInfo->cleanSession == false ) )
+
+ if( status == MQTTSuccess )
{
- LogError( ( "Zero-length client identifier requires cleanSession=true per MQTT 3.1.1." ) );
- status = MQTTBadParameter;
+ pLocalIndex = &pLocalIndex[ variableLengthEncodedSize( propertyLength ) ];
}
- else if( ( pWillInfo != NULL ) && ( pWillInfo->payloadLength > ( size_t ) UINT16_MAX ) )
+
+ if( pPropBuffer != NULL )
{
- /* The MQTTPublishInfo_t is reused for the will message. The payload
- * length for any other message could be larger than 65,535, but
- * the will message length is required to be represented in 2 bytes.
- * By bounding the payloadLength of the will message, the CONNECT
- * packet will never be larger than 327699 bytes. */
- LogError( ( "The Will Message length must not exceed %d. "
- "pWillInfo->payloadLength=%lu.",
- UINT16_MAX,
- ( unsigned long ) pWillInfo->payloadLength ) );
- status = MQTTBadParameter;
+ pPropBuffer->pBuffer = pLocalIndex;
+ pPropBuffer->bufferLength = propertyLength;
+ pPropBuffer->currentIndex = propertyLength;
}
- else
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
{
- /* Add the length of the client identifier. */
- connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
+ uint8_t propertyId = *pLocalIndex;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
- /* Add the lengths of the will message and topic name if provided. */
- if( pWillInfo != NULL )
+ switch( propertyId )
{
+ case MQTT_PAYLOAD_FORMAT_ID:
+ {
+ uint8_t property;
+ status = decodeUint8t( &property, &propertyLength, &payloadFormatIndicator, &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ /* Payload format must only be 0 or 1. */
+ if( property > 1 )
+ {
+ status = MQTTBadResponse;
+ LogError( ( "Payload Format Indicator is not 0x00. " ) );
+ }
+ }
+ }
+ break;
+
+ case MQTT_TOPIC_ALIAS_ID:
+ status = decodeUint16t( &topicAliasVal, &propertyLength, &topicAlias, &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ if( topicAliasVal == 0 )
+ {
+ status = MQTTBadResponse;
+ LogError( ( "Topic Alias value of 0 is not permitted." ) );
+ }
+ }
+
+ break;
+
+ case MQTT_RESPONSE_TOPIC_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &responseTopic, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_CORRELATION_DATA_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &correlationData, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_MSG_EXPIRY_ID:
+ {
+ uint32_t property;
+ status = decodeUint32t( &property, &propertyLength, &messageExpiryInterval, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_CONTENT_TYPE_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &contentType, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_SUBSCRIPTION_ID_ID:
+ status = decodeVariableLength( pLocalIndex, propertyLength, &subscriptionId );
+
+ if( status == MQTTSuccess )
+ {
+ pLocalIndex = &pLocalIndex[ variableLengthEncodedSize( subscriptionId ) ];
+ propertyLength -= variableLengthEncodedSize( subscriptionId );
+ }
+
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * pPropertyKey;
+ size_t propertyKeyLen;
+ const char * pPropertyValue;
+ size_t propertyValueLen;
+ status = decodeUserProp( &pPropertyKey,
+ &propertyKeyLen,
+ &pPropertyValue,
+ &propertyValueLen,
+ &propertyLength,
+ &pLocalIndex );
+ }
+ break;
+
+ default:
+ status = MQTTBadResponse;
+ break;
+ }
+ }
+
+ if( ( status == MQTTSuccess ) && ( topicAlias == true ) )
+ {
+ if( topicAliasMax < topicAliasVal )
+ {
+ status = MQTTBadResponse;
+ LogError( ( "Topic Alias greater than Topic Alias Max. " ) );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t updateContextWithConnectProps( const MQTTPropBuilder_t * pPropBuilder,
+ MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pPropBuilder == NULL )
+ {
+ LogError( ( "pPropBuilder cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pPropBuilder->pBuffer == NULL )
+ {
+ LogError( ( "pPropBuilder->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pConnectProperties == NULL )
+ {
+ LogError( ( "pConnectProperties cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ bool maxPacket = false;
+ bool sessionExpiry = false;
+ bool receiveMax = false;
+ bool topicAlias = false;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex;
+
+ propertyLength = pPropBuilder->currentIndex;
+ pIndex = pPropBuilder->pBuffer; /* Pointer to the buffer */
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pIndex;
+ bool used = false;
+ pIndex = &pIndex[ 1 ];
+ propertyLength--;
+
+ switch( propertyId )
+ {
+ case MQTT_SESSION_EXPIRY_ID:
+
+ /**
+ * This value shall get overwritten if the server sends a sessionExpiry
+ * in the CONNACK.
+ */
+ status = decodeUint32t( &pConnectProperties->sessionExpiry, &propertyLength,
+ &sessionExpiry, &pIndex );
+ break;
+
+ case MQTT_RECEIVE_MAX_ID:
+ status = decodeUint16t( &pConnectProperties->receiveMax, &propertyLength,
+ &receiveMax, &pIndex );
+ break;
+
+ case MQTT_MAX_PACKET_SIZE_ID:
+ status = decodeUint32t( &pConnectProperties->maxPacketSize, &propertyLength,
+ &maxPacket, &pIndex );
+ break;
+
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+ status = decodeUint16t( &pConnectProperties->topicAliasMax, &propertyLength,
+ &topicAlias, &pIndex );
+ break;
+
+ case MQTT_REQUEST_PROBLEM_ID:
+ case MQTT_REQUEST_RESPONSE_ID:
+ {
+ uint8_t property;
+ /* TODO: should this go in the context? */
+ status = decodeUint8t( &property, &propertyLength, &used, &pIndex );
+ }
+ break;
+
+ case MQTT_AUTH_DATA_ID:
+ case MQTT_AUTH_METHOD_ID:
+ {
+ const char * data;
+ size_t dataLength;
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ }
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key,
+ &keyLength,
+ &value,
+ &valueLength,
+ &propertyLength,
+ &pIndex );
+ }
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
+ const MQTTPublishInfo_t * pWillInfo,
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t remainingLength;
+ uint32_t propertyLength = 0U;
+ uint32_t willPropertyLength = 0U;
+
+ /* The CONNECT packet will always include a 10-byte variable header without connect properties. */
+ uint32_t connectPacketSize = MQTT_PACKET_CONNECT_HEADER_SIZE;
+
+ /* Validate arguments. */
+ if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) ||
+ ( pPacketSize == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
+ "pRemainingLength=%p, pPacketSize=%p.",
+ ( void * ) pConnectInfo,
+ ( void * ) pRemainingLength,
+ ( void * ) pPacketSize ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pConnectInfo->clientIdentifierLength == 0U ) ^
+ ( ( pConnectInfo->pClientIdentifier == NULL ) || ( *( pConnectInfo->pClientIdentifier ) == '\0' ) ) )
+ {
+ LogError( ( "Client ID length and value mismatch." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->clientIdentifierLength ) )
+ {
+ LogError( ( "Client ID length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->userNameLength ) )
+ {
+ LogError( ( "User name length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->passwordLength ) )
+ {
+ LogError( ( "Password length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pWillInfo != NULL ) && CHECK_SIZE_T_OVERFLOWS_16BIT( pWillInfo->payloadLength ) )
+ {
+ /* The MQTTPublishInfo_t is reused for the will message. The payload
+ * length for any other message could be larger than 65,535, but
+ * the will message length is required to be represented in 2 bytes. */
+ LogError( ( "The Will Message length must not exceed %d. "
+ "pWillInfo->payloadLength=%lu.",
+ UINT16_MAX,
+ ( unsigned long ) pWillInfo->payloadLength ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pWillInfo != NULL ) && CHECK_SIZE_T_OVERFLOWS_16BIT( pWillInfo->topicNameLength ) )
+ {
+ LogError( ( "Will Topic name length must be less than 65536 according to MQTT spec." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Do Nothing. */
+ }
+
+ if( ( status == MQTTSuccess ) && ( pConnectProperties != NULL ) && ( pConnectProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pConnectProperties->currentIndex ) ||
+ ( pConnectProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Connect properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pConnectProperties->currentIndex;
+ }
+ }
+
+ if( ( status == MQTTSuccess ) && ( pWillProperties != NULL ) && ( pWillProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pWillProperties->currentIndex ) ||
+ ( pWillProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Will properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ willPropertyLength = pWillProperties->currentIndex;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Since property length, client ID length, will property length, will topic name length
+ * and will payload length are ensured to be below their maximum value, connectPacketSize
+ * will not overflow.
+ * Max property length 268435455
+ * Max encoded prop length + 4
+ * Max client ID len (+2 byte len) + 65535 + 2
+ * Max will property length + 268435455
+ * Max will topic name len (+2 byte len) + 65535 + 2
+ * Max will payload len (+2 byte len) + 65535 + 2
+ * Max username length (+2 byte len) + 65535 + 2
+ * Max password length (+2 byte len) + 65535 + 2
+ * Total = 537198599 ( < UINT32_MAX ) */
+
+ /* Add the length of the properties. */
+ connectPacketSize += propertyLength;
+ connectPacketSize += variableLengthEncodedSize( propertyLength );
+
+ /* Add the length of the client identifier. */
+ connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
+
+ /* Add the lengths of the will message, topic name and properties if provided. */
+ if( pWillInfo != NULL )
+ {
+ connectPacketSize += willPropertyLength;
+ connectPacketSize += variableLengthEncodedSize( willPropertyLength );
connectPacketSize += pWillInfo->topicNameLength + sizeof( uint16_t ) +
pWillInfo->payloadLength + sizeof( uint16_t );
}
@@ -1758,24 +3119,24 @@ MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
/* Calculate the full size of the MQTT CONNECT packet by adding the size of
* the "Remaining Length" field plus 1 byte for the "Packet Type" field. */
- connectPacketSize += 1U + remainingLengthEncodedSize( connectPacketSize );
-
- /* The connectPacketSize calculated from this function's parameters is
- * guaranteed to be less than the maximum MQTT CONNECT packet size, which
- * is 327700. If the maximum client identifier length, the maximum will
- * message topic length, the maximum will topic payload length, the
- * maximum username length, and the maximum password length are all present
- * in the MQTT CONNECT packet, the total size will be calculated to be
- * 327699:
- * (variable length header)10 +
- * (maximum client identifier length) 65535 + (encoded length) 2 +
- * (maximum will message topic name length) 65535 + (encoded length)2 +
- * (maximum will message payload length) 65535 + 2 +
- * (maximum username length) 65535 + (encoded length) 2 +
- * (maximum password length) 65535 + (encoded length) 2 +
- * (packet type field length) 1 +
- * (CONNECT packet encoded length) 3 = 327699 */
+ connectPacketSize += 1U + variableLengthEncodedSize( connectPacketSize );
+
+ /*
+ * It is possible that the remaining length becomes more than the maximum
+ * allowed by the MQTTV5-Spec, i.e. 268,435,455. This is because the user may
+ * enter a large number of user properties for the connect packet and/or
+ * the last will.
+ * Hence we need to have a check for this case
+ */
+ if( remainingLength > MQTT_MAX_REMAINING_LENGTH )
+ {
+ LogError( ( "Packet remaining length exceeds the maximum allowed size." ) );
+ status = MQTTBadParameter;
+ }
+ }
+ if( status == MQTTSuccess )
+ {
*pRemainingLength = remainingLength;
*pPacketSize = connectPacketSize;
@@ -1789,13 +3150,168 @@ MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
/*-----------------------------------------------------------*/
+static MQTTStatus_t decodePubAckProperties( MQTTPropBuilder_t * pPropBuffer,
+ uint8_t * pIndex,
+ uint32_t remainingLength )
+{
+ uint32_t propertyLength = 0U;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pLocalIndex = pIndex;
+ bool reasonString = false;
+
+ /* Decode the property length */
+ status = decodeVariableLength( pLocalIndex, remainingLength, &propertyLength );
+
+ if( status == MQTTSuccess )
+ {
+ /* Validate the remaining length. Since properties are the last in the MQTT packet
+ * the length which is remaining must be:
+ * Bytes taken to encode the property length +
+ * The actual length of the properties
+ */
+ if( remainingLength != ( propertyLength + variableLengthEncodedSize( propertyLength ) ) )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ pLocalIndex = &pLocalIndex[ variableLengthEncodedSize( propertyLength ) ];
+ }
+ }
+
+ if( ( pPropBuffer != NULL ) && ( status == MQTTSuccess ) )
+ {
+ pPropBuffer->pBuffer = pLocalIndex;
+ pPropBuffer->bufferLength = propertyLength;
+ }
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ /* Decode the property id. */
+ uint8_t propertyId = *pLocalIndex;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_REASON_STRING_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &reasonString, &pLocalIndex );
+ break;
+ }
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * pPropertyKey;
+ size_t propertyKeyLen;
+ const char * pPropertyValue;
+ size_t propertyValueLen;
+ status = decodeUserProp( &pPropertyKey,
+ &propertyKeyLen,
+ &pPropertyValue,
+ &propertyValueLen,
+ &propertyLength,
+ &pLocalIndex );
+ break;
+ }
+
+ default:
+ status = MQTTBadResponse;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateDisconnectResponse( MQTTSuccessFailReasonCode_t reasonCode,
+ bool incoming )
+{
+ MQTTStatus_t status;
+
+ /* Validate the reason code. */
+ /* coverity[misra_c_2012_rule_10_5_violation] */
+ switch( reasonCode )
+ {
+ case MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE:
+
+ if( incoming == true )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ status = MQTTSuccess;
+ }
+
+ break;
+
+ case MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION:
+ case MQTT_REASON_DISCONNECT_UNSPECIFIED_ERROR:
+ case MQTT_REASON_DISCONNECT_MALFORMED_PACKET:
+ case MQTT_REASON_DISCONNECT_PROTOCOL_ERROR:
+ case MQTT_REASON_DISCONNECT_IMPLEMENTATION_SPECIFIC_ERROR:
+ case MQTT_REASON_DISCONNECT_TOPIC_NAME_INVALID:
+ case MQTT_REASON_DISCONNECT_RECEIVE_MAXIMUM_EXCEEDED:
+ case MQTT_REASON_DISCONNECT_TOPIC_ALIAS_INVALID:
+ case MQTT_REASON_DISCONNECT_PACKET_TOO_LARGE:
+ case MQTT_REASON_DISCONNECT_MESSAGE_RATE_TOO_HIGH:
+ case MQTT_REASON_DISCONNECT_QUOTA_EXCEEDED:
+ case MQTT_REASON_DISCONNECT_ADMINISTRATIVE_ACTION:
+ case MQTT_REASON_DISCONNECT_PAYLOAD_FORMAT_INVALID:
+ status = MQTTSuccess;
+ break;
+
+ case MQTT_REASON_DISCONNECT_NOT_AUTHORIZED:
+ case MQTT_REASON_DISCONNECT_SERVER_BUSY:
+ case MQTT_REASON_DISCONNECT_SERVER_SHUTTING_DOWN:
+ case MQTT_REASON_DISCONNECT_KEEP_ALIVE_TIMEOUT:
+ case MQTT_REASON_DISCONNECT_SESSION_TAKEN_OVER:
+ case MQTT_REASON_DISCONNECT_TOPIC_FILTER_INVALID:
+ case MQTT_REASON_DISCONNECT_RETAIN_NOT_SUPPORTED:
+ case MQTT_REASON_DISCONNECT_QOS_NOT_SUPPORTED:
+ case MQTT_REASON_DISCONNECT_USE_ANOTHER_SERVER:
+ case MQTT_REASON_DISCONNECT_SERVER_MOVED:
+ case MQTT_REASON_DISCONNECT_MAXIMUM_CONNECT_TIME:
+ case MQTT_REASON_DISCONNECT_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED:
+ case MQTT_REASON_DISCONNECT_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED:
+ case MQTT_REASON_DISCONNECT_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED:
+ case MQTT_REASON_DISCONNECT_BAD_AUTHENTICATION_METHOD:
+
+ if( incoming == true )
+ {
+ status = MQTTSuccess;
+ }
+ else
+ {
+ status = MQTTBadParameter;
+ }
+
+ break;
+
+ default:
+ status = MQTTBadResponse;
+ break;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
MQTTStatus_t status = MQTTSuccess;
- size_t connectPacketSize = 0;
+ uint32_t connectPacketSize = 0;
/* Validate arguments. */
if( ( pConnectInfo == NULL ) || ( pFixedBuffer == NULL ) )
@@ -1817,12 +3333,32 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
LogError( ( "pWillInfo->pTopicName cannot be NULL if Will is present." ) );
status = MQTTBadParameter;
}
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->clientIdentifierLength ) )
+ {
+ LogError( ( "clientIdentifierLength must be less than 65536 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->userNameLength ) )
+ {
+ LogError( ( "userNameLength must be less than 65536 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pConnectInfo->passwordLength ) )
+ {
+ LogError( ( "passwordLength must be less than 65536 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pWillInfo != NULL ) && CHECK_SIZE_T_OVERFLOWS_16BIT( pWillInfo->topicNameLength ) )
+ {
+ LogError( ( "topicNameLength must be less than 65536 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
else
{
/* Calculate CONNECT packet size. Overflow in in this addition is not checked
* because it is part of the API contract to call Mqtt_GetConnectPacketSize()
* before this function. */
- connectPacketSize = remainingLength + remainingLengthEncodedSize( remainingLength ) + 1U;
+ connectPacketSize = remainingLength + variableLengthEncodedSize( remainingLength ) + 1U;
/* Check that the full packet size fits within the given buffer. */
if( connectPacketSize > pFixedBuffer->size )
@@ -1837,6 +3373,8 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
{
serializeConnectPacket( pConnectInfo,
pWillInfo,
+ pConnectProperties,
+ pWillProperties,
remainingLength,
pFixedBuffer );
}
@@ -1849,35 +3387,59 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize )
+ const MQTTPropBuilder_t * pSubscribeProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
- /* Validate parameters. */
- if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
- ( pPacketSize == NULL ) )
+ if( pSubscriptionList == NULL )
{
- LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
- "pRemainingLength=%p, pPacketSize=%p.",
- ( void * ) pSubscriptionList,
- ( void * ) pRemainingLength,
- ( void * ) pPacketSize ) );
+ LogError( ( "Argument cannot be null : SubscriptionList" ) );
status = MQTTBadParameter;
}
else if( subscriptionCount == 0U )
{
- LogError( ( "subscriptionCount is 0." ) );
+ LogError( ( "Subscription count cannot be 0" ) );
+ status = MQTTBadParameter;
+ }
+ else if( maxPacketSize == 0U )
+ {
+ LogError( ( "Max Packet size cannot be 0" ) );
+ status = MQTTBadParameter;
+ }
+ else if( pRemainingLength == NULL )
+ {
+ LogError( ( "Pointer to remaining length cannot be NULL." ) );
status = MQTTBadParameter;
}
else
{
- /* Calculate the MQTT SUBSCRIBE packet size. */
- status = calculateSubscriptionPacketSize( pSubscriptionList,
- subscriptionCount,
- pRemainingLength,
- pPacketSize,
- MQTT_SUBSCRIBE );
+ if( ( pSubscribeProperties != NULL ) && ( pSubscribeProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pSubscribeProperties->currentIndex ) ||
+ ( pSubscribeProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Subscription properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pSubscribeProperties->currentIndex;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ status = calculateSubscriptionPacketSize( pSubscriptionList, subscriptionCount,
+ pRemainingLength, pPacketSize, propertyLength,
+ maxPacketSize, MQTT_TYPE_SUBSCRIBE );
+ }
}
return status;
@@ -1885,87 +3447,107 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
/*-----------------------------------------------------------*/
-uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId )
-{
- uint8_t * pIterator = pIndex;
-
- /* The first byte in SUBSCRIBE is the packet type. */
- *pIterator = MQTT_PACKET_TYPE_SUBSCRIBE;
- pIterator++;
-
- /* Encode the "Remaining length" starting from the second byte. */
- pIterator = encodeRemainingLength( pIterator, remainingLength );
-
- /* Place the packet identifier into the SUBSCRIBE packet. */
- pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
- pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
- /* Advance the pointer. */
- pIterator = &pIterator[ 2 ];
-
- return pIterator;
-}
-
-/*-----------------------------------------------------------*/
-
-uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId )
-{
- uint8_t * pIterator = pIndex;
-
- /* The first byte in UNSUBSCRIBE is the packet type. */
- *pIterator = MQTT_PACKET_TYPE_UNSUBSCRIBE;
- pIterator++;
-
- /* Encode the "Remaining length" starting from the second byte. */
- pIterator = encodeRemainingLength( pIterator, remainingLength );
-
- /* Place the packet identifier into the SUBSCRIBE packet. */
- pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
- pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
- /* Increment the pointer. */
- pIterator = &pIterator[ 2 ];
-
- return pIterator;
-}
-
MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
+ const MQTTPropBuilder_t * pSubscribeProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
size_t i = 0;
uint8_t * pIndex = NULL;
+ size_t propertyLength = 0U;
+ MQTTStatus_t status;
- /* Validate all the parameters. */
- MQTTStatus_t status =
- validateSubscriptionSerializeParams( pSubscriptionList,
- subscriptionCount,
- packetId,
- remainingLength,
- pFixedBuffer );
-
- if( status == MQTTSuccess )
+ if( ( pSubscribeProperties != NULL ) && ( pSubscribeProperties->pBuffer != NULL ) )
{
- pIndex = pFixedBuffer->pBuffer;
+ propertyLength = pSubscribeProperties->currentIndex;
+ }
+
+ /* Validate all the parameters. */
+ status = validateSubscriptionSerializeParams( pSubscriptionList,
+ subscriptionCount,
+ packetId,
+ remainingLength,
+ pFixedBuffer );
- pIndex = MQTT_SerializeSubscribeHeader( remainingLength,
- pIndex,
- packetId );
+ if( status == MQTTSuccess )
+ {
+ pIndex = pFixedBuffer->pBuffer;
+
+ pIndex = serializeSubscribeHeader( remainingLength,
+ pIndex,
+ packetId );
+ /* Serialize properties. */
+ pIndex = encodeVariableLength( pIndex, propertyLength );
+
+ if( propertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pSubscribeProperties->pBuffer, propertyLength );
+ pIndex = &pIndex[ propertyLength ];
+ }
/* Serialize each subscription topic filter and QoS. */
for( i = 0; i < subscriptionCount; i++ )
{
+ uint8_t subscriptionOptions = 0U;
pIndex = encodeString( pIndex,
pSubscriptionList[ i ].pTopicFilter,
pSubscriptionList[ i ].topicFilterLength );
- /* Place the QoS in the SUBSCRIBE packet. */
- *pIndex = ( uint8_t ) ( pSubscriptionList[ i ].qos );
- pIndex++;
+ /* Place the subscription options. */
+ if( pSubscriptionList[ i ].qos == MQTTQoS1 )
+ {
+ LogInfo( ( "Adding QoS as QoS 1 in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_QOS1 );
+ }
+ else if( pSubscriptionList[ i ].qos == MQTTQoS2 )
+ {
+ LogInfo( ( "Adding QoS as QoS 2 in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_QOS2 );
+ }
+ else
+ {
+ LogInfo( ( "Adding QoS as QoS 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( pSubscriptionList[ i ].noLocalOption )
+ {
+ LogInfo( ( "Adding noLocalOption in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_NO_LOCAL );
+ }
+ else
+ {
+ LogDebug( ( "Adding noLocalOption as 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( pSubscriptionList[ i ].retainAsPublishedOption )
+ {
+ LogInfo( ( " retainAsPublishedOption in SUBSCRIBE payload" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_AS_PUBLISHED );
+ }
+ else
+ {
+ LogDebug( ( "retainAsPublishedOption as 0 in SUBSCRIBE payload" ) );
+ }
+
+ if( pSubscriptionList[ i ].retainHandlingOption == retainSendOnSub )
+ {
+ LogInfo( ( "Send Retain messages at the time of subscribe" ) );
+ }
+ else if( pSubscriptionList[ i ].retainHandlingOption == retainSendOnSubIfNotPresent )
+ {
+ LogInfo( ( "Send retained messages at subscribe only if the subscription does not currently exist" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_HANDLING1 );
+ }
+ else
+ {
+ LogInfo( ( "Do not send retained messages at subscribe" ) );
+ UINT8_SET_BIT( subscriptionOptions, MQTT_SUBSCRIBE_RETAIN_HANDLING2 );
+ }
+
+ *pIndex = subscriptionOptions;
+ pIndex = &pIndex[ 1 ];
}
LogDebug( ( "Length of serialized SUBSCRIBE packet is %lu.",
@@ -1979,10 +3561,13 @@ MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionL
MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize )
+ const MQTTPropBuilder_t * pUnsubscribeProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
/* Validate parameters. */
if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
@@ -1995,6 +3580,11 @@ MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscri
( void * ) pPacketSize ) );
status = MQTTBadParameter;
}
+ else if( maxPacketSize == 0U )
+ {
+ LogError( ( "Max Packet size cannot be 0" ) );
+ status = MQTTBadParameter;
+ }
else if( subscriptionCount == 0U )
{
LogError( ( "Subscription count is 0." ) );
@@ -2002,12 +3592,88 @@ MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscri
}
else
{
- /* Calculate the MQTT UNSUBSCRIBE packet size. */
- status = calculateSubscriptionPacketSize( pSubscriptionList,
- subscriptionCount,
- pRemainingLength,
- pPacketSize,
- MQTT_UNSUBSCRIBE );
+ if( ( pUnsubscribeProperties != NULL ) && ( pUnsubscribeProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pUnsubscribeProperties->currentIndex ) ||
+ ( pUnsubscribeProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Un-Subscription properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pUnsubscribeProperties->currentIndex;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Calculate the MQTT UNSUBSCRIBE packet size. */
+ status = calculateSubscriptionPacketSize( pSubscriptionList,
+ subscriptionCount,
+ pRemainingLength,
+ pPacketSize,
+ propertyLength,
+ maxPacketSize,
+ MQTT_TYPE_UNSUBSCRIBE );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ValidateUnsubscribeProperties( const MQTTPropBuilder_t * pPropertyBuilder )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex = NULL;
+
+
+ if( ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
+ {
+ propertyLength = pPropertyBuilder->currentIndex;
+ pIndex = pPropertyBuilder->pBuffer;
+ }
+ else if( ( pPropertyBuilder != NULL ) &&
+ ( ( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ) ||
+ ( pPropertyBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) ) )
+ {
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pIndex;
+ pIndex = &pIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key, &keyLength, &value, &valueLength, &propertyLength, &pIndex );
+
+ if( status == MQTTSuccess )
+ {
+ LogTrace( ( "Processing User Property %.*s:%.*s",
+ ( int ) keyLength, key,
+ ( int ) valueLength, value ) );
+ }
+ }
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ break;
+ }
}
return status;
@@ -2017,14 +3683,21 @@ MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscri
MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
+ const MQTTPropBuilder_t * pUnsubscribeProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
MQTTStatus_t status = MQTTSuccess;
size_t i = 0;
+ size_t propertyLength = 0;
uint8_t * pIndex = NULL;
+ if( ( pUnsubscribeProperties != NULL ) && ( pUnsubscribeProperties->pBuffer != NULL ) )
+ {
+ propertyLength = pUnsubscribeProperties->currentIndex;
+ }
+
/* Validate all the parameters. */
status = validateSubscriptionSerializeParams( pSubscriptionList,
subscriptionCount,
@@ -2037,7 +3710,16 @@ MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptio
/* Get the start of the buffer to the iterator variable. */
pIndex = pFixedBuffer->pBuffer;
- pIndex = MQTT_SerializeUnsubscribeHeader( remainingLength, pIndex, packetId );
+ pIndex = serializeUnsubscribeHeader( remainingLength, pIndex, packetId );
+
+ /* Serialize the properties. */
+ pIndex = encodeVariableLength( pIndex, propertyLength );
+
+ if( propertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pUnsubscribeProperties->pBuffer, propertyLength );
+ pIndex = &pIndex[ propertyLength ];
+ }
/* Serialize each subscription topic filter. */
for( i = 0; i < subscriptionCount; i++ )
@@ -2057,10 +3739,30 @@ MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptio
/*-----------------------------------------------------------*/
MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize )
+ const MQTTPropBuilder_t * pPublishProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+
+ if( ( pPublishProperties != NULL ) && ( pPublishProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pPublishProperties->currentIndex ) ||
+ ( pPublishProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Publish properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pPublishProperties->currentIndex;
+ }
+ }
if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
{
@@ -2071,25 +3773,15 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
( void * ) pPacketSize ) );
status = MQTTBadParameter;
}
- else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) )
{
- LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
- "topicNameLength=%hu.",
- ( void * ) pPublishInfo->pTopicName,
- ( unsigned short ) pPublishInfo->topicNameLength ) );
+ LogError( ( "Topic name length must be smaller than 65535." ) );
status = MQTTBadParameter;
}
else
{
- /* Calculate the "Remaining length" field and total packet size. If it exceeds
- * what is allowed in the MQTT standard, return an error. */
- if( calculatePublishPacketSize( pPublishInfo, pRemainingLength, pPacketSize ) == false )
- {
- LogError( ( "PUBLISH packet remaining length exceeds %lu, which is the "
- "maximum size allowed by MQTT 3.1.1.",
- MQTT_MAX_REMAINING_LENGTH ) );
- status = MQTTBadParameter;
- }
+ status = calculatePublishPacketSize( pPublishInfo, pRemainingLength,
+ pPacketSize, maxPacketSize, propertyLength );
}
return status;
@@ -2098,8 +3790,9 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
/*-----------------------------------------------------------*/
MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
+ const MQTTPropBuilder_t * pPublishProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer )
{
MQTTStatus_t status = MQTTSuccess;
@@ -2149,12 +3842,17 @@ MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
status = MQTTBadParameter;
}
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) )
+ {
+ LogError( ( "topicNameLength must be less than 65535 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
else
{
/* Length of serialized packet = First byte
* + Length of encoded remaining length
* + Remaining length. */
- packetSize = 1U + remainingLengthEncodedSize( remainingLength )
+ packetSize = 1U + variableLengthEncodedSize( remainingLength )
+ remainingLength;
}
@@ -2171,6 +3869,7 @@ MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
{
/* Serialize publish with header and payload. */
serializePublishCommon( pPublishInfo,
+ pPublishProperties,
remainingLength,
packetId,
pFixedBuffer,
@@ -2183,8 +3882,9 @@ MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
/*-----------------------------------------------------------*/
MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
+ const MQTTPropBuilder_t * pPublishProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer,
size_t * pHeaderSize )
{
@@ -2215,6 +3915,11 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
( unsigned short ) pPublishInfo->topicNameLength ) );
status = MQTTBadParameter;
}
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) )
+ {
+ LogError( ( "topicNameLength must be less than 65535 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
{
LogError( ( "Packet Id is 0 for publish with QoS=%hu.",
@@ -2233,7 +3938,7 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
* + Remaining length
* - Payload Length.
*/
- packetSize = 1U + remainingLengthEncodedSize( remainingLength )
+ packetSize = 1U + variableLengthEncodedSize( remainingLength )
+ remainingLength
- pPublishInfo->payloadLength;
}
@@ -2251,6 +3956,7 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
{
/* Serialize publish without copying the payload. */
serializePublishCommon( pPublishInfo,
+ pPublishProperties,
remainingLength,
packetId,
pFixedBuffer,
@@ -2267,7 +3973,9 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
uint8_t packetType,
- uint16_t packetId )
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pAckProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode )
{
MQTTStatus_t status = MQTTSuccess;
@@ -2292,6 +4000,23 @@ MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
LogError( ( "Packet ID cannot be 0." ) );
status = MQTTBadParameter;
}
+ else if( ( pReasonCode == NULL ) && ( pAckProperties != NULL ) )
+ {
+ LogError( ( "A reason code must be provided if there are properties." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pReasonCode != NULL ) && ( validateReasonCodeForAck( packetType, *pReasonCode ) != MQTTSuccess ) )
+ {
+ LogError( ( "Invalid reason code for the ACK type." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pAckProperties != NULL ) &&
+ ( CHECK_SIZE_T_OVERFLOWS_32BIT( pAckProperties->currentIndex ) ||
+ ( pAckProperties->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) ) )
+ {
+ LogError( ( "ACK properties must be smaller than 268435456." ) );
+ status = MQTTBadParameter;
+ }
else
{
switch( packetType )
@@ -2305,6 +4030,36 @@ MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
pFixedBuffer->pBuffer[ 1 ] = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
pFixedBuffer->pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetId );
pFixedBuffer->pBuffer[ 3 ] = UINT16_LOW_BYTE( packetId );
+
+ if( pReasonCode != NULL )
+ {
+ if( pFixedBuffer->size < ( MQTT_PUBLISH_ACK_PACKET_SIZE + 1U ) )
+ {
+ LogError( ( "Not enough space for reason code." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pFixedBuffer->pBuffer[ 4 ] = *pReasonCode;
+
+ if( ( pAckProperties == NULL ) || ( pAckProperties->pBuffer == NULL ) )
+ {
+ /* No properties to be added. */
+ }
+ /* Size is calculated as PUBACK + 1 byte for reason code + properties. */
+ else if( pFixedBuffer->size <
+ getAckPacketSize( pAckProperties ) )
+ {
+ LogError( ( "Not enough space in the buffer to encode properties." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ memcpy( &pFixedBuffer->pBuffer[ 5 ], pAckProperties->pBuffer, pAckProperties->currentIndex );
+ }
+ }
+ }
+
break;
default:
@@ -2320,19 +4075,110 @@ MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize )
+MQTTStatus_t MQTT_GetDisconnectPacketSize( const MQTTPropBuilder_t * pDisconnectProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ MQTTSuccessFailReasonCode_t * pReasonCode )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t length = 0U;
+ uint32_t packetSize = 0U;
+ uint32_t propertyLength = 0U;
- if( pPacketSize == NULL )
+ /* Validate the arguments. */
+ if( ( pReasonCode == NULL ) && ( pDisconnectProperties != NULL ) )
{
- LogError( ( "pPacketSize is NULL." ) );
+ LogError( ( "Reason code must be specified if the properties are non-NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL:"
+ "pRemainingLength=%p, pPacketSize=%p.",
+ ( void * ) pRemainingLength,
+ ( void * ) pPacketSize ) );
status = MQTTBadParameter;
}
+ else if( maxPacketSize == 0U )
+ {
+ LogError( ( "Max packet size cannot be zero." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pReasonCode != NULL ) && ( validateDisconnectResponse( *pReasonCode, false ) != MQTTSuccess ) )
+ {
+ LogError( ( "Invalid reason code." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pReasonCode != NULL )
+ {
+ /* Reason code. */
+ length += 1U;
+ }
else
{
- /* MQTT DISCONNECT packets always have the same size. */
- *pPacketSize = MQTT_DISCONNECT_PACKET_SIZE;
+ /* No reason code provided. No need to update the length. */
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( ( pDisconnectProperties != NULL ) && ( pDisconnectProperties->pBuffer != NULL ) )
+ {
+ /* The value must fit in a 32-bit variable all the while being small enough to
+ * be properly encoded in a variable integer format. */
+ if( CHECK_SIZE_T_OVERFLOWS_32BIT( pDisconnectProperties->currentIndex ) ||
+ ( pDisconnectProperties->currentIndex > MQTT_MAX_REMAINING_LENGTH ) )
+ {
+ LogError( ( "Disconnect properties must be less than 268435456 "
+ "to be able to fit in a MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pDisconnectProperties->currentIndex;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Validate the length. The sum of:
+ * Bytes required to encode the properties +
+ * Actual properties +
+ * Optional reason code (which is depicted by length)
+ *
+ * Must be less than the maximum allowed remaining length.
+ */
+ if( ( propertyLength + variableLengthEncodedSize( propertyLength ) + length ) < MQTT_MAX_REMAINING_LENGTH )
+ {
+ length += variableLengthEncodedSize( propertyLength ) + propertyLength;
+ *pRemainingLength = length;
+ }
+ else
+ {
+ LogError( ( "The properties + reason code cannot fit in MQTT_MAX_REMAINING_LENGTH bytes." ) );
+ status = MQTTBadParameter;
+ }
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Packet size should be less than max allowed by the server. It is calculated as:
+ * MQTT Disconnect header byte +
+ * Bytes required to encode the remaining length +
+ * The remaining length (which includes properties and error code).
+ */
+ packetSize = 1U + variableLengthEncodedSize( length ) + length;
+
+ if( packetSize > maxPacketSize )
+ {
+ LogError( ( "Packet Size greater than Max Packet Size specified in the CONNACK" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ *pPacketSize = packetSize;
+ }
}
return status;
@@ -2340,9 +4186,20 @@ MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize )
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTPropBuilder_t * pDisconnectProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTFixedBuffer_t * pFixedBuffer )
{
MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pIndex = NULL;
+ size_t packetSize = 0;
+ size_t propertyLength = 0;
+
+ if( ( pDisconnectProperties != NULL ) && ( pDisconnectProperties->pBuffer != NULL ) )
+ {
+ propertyLength = pDisconnectProperties->currentIndex;
+ }
/* Validate arguments. */
if( pFixedBuffer == NULL )
@@ -2355,27 +4212,45 @@ MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
status = MQTTBadParameter;
}
+ else if( ( pReasonCode == NULL ) && ( pDisconnectProperties != NULL ) )
+ {
+ LogError( ( "Reason code must be provided if the properties are non-NULL." ) );
+ status = MQTTBadParameter;
+ }
else
{
- /* Empty else MISRA 15.7 */
+ /* Length of serialized packet = First byte
+ * + Length of encoded remaining length
+ * + Remaining length. */
+ packetSize = 1U + variableLengthEncodedSize( remainingLength ) + remainingLength;
}
if( status == MQTTSuccess )
{
- if( pFixedBuffer->size < MQTT_DISCONNECT_PACKET_SIZE )
+ if( pFixedBuffer->size < packetSize )
{
LogError( ( "Buffer size of %lu is not sufficient to hold "
"serialized DISCONNECT packet of size of %lu.",
( unsigned long ) pFixedBuffer->size,
- MQTT_DISCONNECT_PACKET_SIZE ) );
+ ( unsigned long ) packetSize ) );
status = MQTTNoMemory;
}
}
if( status == MQTTSuccess )
{
- pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
- pFixedBuffer->pBuffer[ 1 ] = MQTT_DISCONNECT_REMAINING_LENGTH;
+ pIndex = pFixedBuffer->pBuffer;
+ pIndex = serializeDisconnectFixed( pIndex,
+ pReasonCode,
+ remainingLength );
+
+ pIndex = encodeVariableLength( pIndex, propertyLength );
+
+ if( propertyLength > 0U )
+ {
+ ( void ) memcpy( ( void * ) pIndex, ( const void * ) pDisconnectProperties->pBuffer, propertyLength );
+ pIndex = &pIndex[ propertyLength ];
+ }
}
return status;
@@ -2383,7 +4258,7 @@ MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize )
+MQTTStatus_t MQTT_GetPingreqPacketSize( uint32_t * pPacketSize )
{
MQTTStatus_t status = MQTTSuccess;
@@ -2403,42 +4278,1099 @@ MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize )
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer )
+MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pFixedBuffer == NULL )
+ {
+ LogError( ( "pFixedBuffer is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pFixedBuffer->pBuffer == NULL )
+ {
+ LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* All parameters are good. */
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( pFixedBuffer->size < MQTT_PACKET_PINGREQ_SIZE )
+ {
+ LogError( ( "Buffer size of %lu is not sufficient to hold "
+ "serialized PINGREQ packet of size of %lu.",
+ ( unsigned long ) pFixedBuffer->size,
+ MQTT_PACKET_PINGREQ_SIZE ) );
+ status = MQTTNoMemory;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Ping request packets are always the same. */
+ pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_PINGREQ;
+ pFixedBuffer->pBuffer[ 1 ] = 0x00;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+ uint16_t * pPacketId,
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * propBuffer,
+ uint32_t maxPacketSize,
+ uint16_t topicAliasMax )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( ( pIncomingPacket == NULL ) || ( pPacketId == NULL ) || ( pPublishInfo == NULL ) )
+ {
+ LogError( ( "Argument cannot be NULL: pIncomingPacket=%p, "
+ "pPacketId=%p, pPublishInfo=%p",
+ ( void * ) pIncomingPacket,
+ ( void * ) pPacketId,
+ ( void * ) pPublishInfo ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pIncomingPacket->type & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+ {
+ LogError( ( "Packet is not publish. Packet type: %02x.",
+ ( unsigned int ) pIncomingPacket->type ) );
+ status = MQTTBadParameter;
+ }
+ else if( pIncomingPacket->pRemainingData == NULL )
+ {
+ LogError( ( "Argument cannot be NULL: "
+ "pIncomingPacket->pRemainingData is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pIncomingPacket->remainingLength >= MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "Remaining length cannot be larger than MQTT maximum (268435456)." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pIncomingPacket->remainingLength +
+ variableLengthEncodedSize( pIncomingPacket->remainingLength ) +
+ 1U ) > maxPacketSize )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ status = deserializePublish( pIncomingPacket, pPacketId, pPublishInfo, propBuffer, topicAliasMax );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_DeserializeConnAck( const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropBuffer,
+ MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pIncomingPacket == NULL )
+ {
+ LogError( ( "pIncomingPacket cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pConnectProperties == NULL )
+ {
+ LogError( ( "pConnectProperties cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pIncomingPacket->type != MQTT_PACKET_TYPE_CONNACK )
+ {
+ LogError( ( "MQTT_DeserializeConnAck should only be used to deserialize CONNACK packet." ) );
+ status = MQTTBadParameter;
+ }
+ /* Pointer for session present cannot be NULL for CONNACK. */
+ else if( pSessionPresent == NULL )
+ {
+ LogError( ( "pSessionPresent cannot be NULL for CONNACK packet." ) );
+ status = MQTTBadParameter;
+ }
+
+ /* Pointer for remaining data cannot be NULL for packets other
+ * than PINGRESP. */
+ else if( pIncomingPacket->pRemainingData == NULL )
+ {
+ LogError( ( "Remaining data of incoming CONNACK packet is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ /* Max packet size cannot be 0. */
+ else if( pConnectProperties->maxPacketSize == 0U )
+ {
+ LogError( ( "Max packet size cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pIncomingPacket->remainingLength +
+ variableLengthEncodedSize( pIncomingPacket->remainingLength ) +
+ 1U ) > pConnectProperties->maxPacketSize )
+ {
+ LogError( ( "Incoming CONNACK packet Size cannot be greater than max packet size. " ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ status = deserializeConnack( pConnectProperties,
+ pIncomingPacket,
+ pSessionPresent,
+ pPropBuffer );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
+ uint16_t * pPacketId,
+ MQTTReasonCodeInfo_t * pReasonCode,
+ MQTTPropBuilder_t * pPropBuffer,
+ MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pIncomingPacket == NULL )
+ {
+ LogError( ( "pIncomingPacket cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pReasonCode == NULL )
+ {
+ LogError( ( "pReasonCode cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pConnectProperties == NULL )
+ {
+ LogError( ( "pConnectProperties cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK )
+ {
+ LogError( ( "Please use MQTT_DeserializeConnAck for CONNACK packet." ) );
+ status = MQTTBadParameter;
+ }
+
+ /* Pointer for packet identifier cannot be NULL for packets other than
+ * CONNACK and PINGRESP. This function must not be called for CONNACK
+ * handling and thus only PINGRESP is checked below. */
+ else if( ( pPacketId == NULL ) &&
+ ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
+ {
+ LogError( ( "pPacketId cannot be NULL for packet type %02x.",
+ ( unsigned int ) pIncomingPacket->type ) );
+ status = MQTTBadParameter;
+ }
+
+ /* Pointer for remaining data cannot be NULL for packets other
+ * than PINGRESP. */
+ else if( ( pIncomingPacket->pRemainingData == NULL ) &&
+ ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
+ {
+ LogError( ( "Remaining data of incoming packet is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ /* Max packet size cannot be 0. */
+ else if( pConnectProperties->maxPacketSize == 0U )
+ {
+ LogError( ( "Max packet size cannot be 0." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pIncomingPacket->remainingLength +
+ variableLengthEncodedSize( pIncomingPacket->remainingLength ) +
+ 1U ) > pConnectProperties->maxPacketSize )
+ {
+ LogError( ( "Packet Size cannot be greater than max packet size." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ /* Make sure response packet is a valid ack. */
+ switch( pIncomingPacket->type )
+ {
+ case MQTT_PACKET_TYPE_PUBACK:
+ case MQTT_PACKET_TYPE_PUBREC:
+ case MQTT_PACKET_TYPE_PUBREL:
+ case MQTT_PACKET_TYPE_PUBCOMP:
+ status = deserializePubAcks( pIncomingPacket,
+ pPacketId,
+ pReasonCode,
+ pConnectProperties->requestProblemInfo,
+ pPropBuffer );
+
+ if( ( status == MQTTSuccess ) && ( pIncomingPacket->remainingLength > 2U ) )
+ {
+ status = logAckResponse( *pReasonCode->reasonCode, *pPacketId );
+ }
+
+ break;
+
+ case MQTT_PACKET_TYPE_SUBACK:
+ case MQTT_PACKET_TYPE_UNSUBACK:
+ status = deserializeSubUnsubAck( pIncomingPacket, pPacketId, pReasonCode, pPropBuffer );
+ break;
+
+ case MQTT_PACKET_TYPE_PINGRESP:
+ status = deserializePingresp( pIncomingPacket );
+ break;
+
+ /* Any other packet type is invalid. */
+ default:
+ LogError( ( "Function called with unknown packet type:(%02x).",
+ ( unsigned int ) pIncomingPacket->type ) );
+ status = MQTTBadResponse;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
+ NetworkContext_t * pNetworkContext,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ int32_t bytesReceived = 0;
+
+ if( pIncomingPacket == NULL )
+ {
+ LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Read a single byte. */
+ bytesReceived = readFunc( pNetworkContext,
+ &( pIncomingPacket->type ),
+ 1U );
+ }
+
+ if( bytesReceived == 1 )
+ {
+ /* Check validity. */
+ if( incomingPacketValid( pIncomingPacket->type ) == true )
+ {
+ uint32_t remainingLengthU32;
+
+ remainingLengthU32 = getRemainingLength( readFunc,
+ pNetworkContext );
+
+ if( CHECK_U32T_OVERFLOWS_SIZE_T( remainingLengthU32 ) )
+ {
+ LogError( ( "Incoming packet Remaining length will overflow the size_t variable." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ pIncomingPacket->remainingLength = remainingLengthU32;
+
+ if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "Incoming packet remaining length invalid." ) );
+ status = MQTTBadResponse;
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Incoming packet invalid: Packet type=%u.",
+ ( unsigned int ) pIncomingPacket->type ) );
+ status = MQTTBadResponse;
+ }
+ }
+ else if( ( status != MQTTBadParameter ) && ( bytesReceived == 0 ) )
+ {
+ status = MQTTNoDataAvailable;
+ }
+
+ /* If the input packet was valid, then any other number of bytes received is
+ * a failure. */
+ else if( status != MQTTBadParameter )
+ {
+ LogError( ( "A single byte was not read from the transport: "
+ "transportStatus=%ld.",
+ ( long int ) bytesReceived ) );
+ status = MQTTRecvFailed;
+ }
+ else
+ {
+ /* Input was invalid. */
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader,
+ bool set )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pHeader == NULL )
+ {
+ LogError( ( "Header cannot be NULL" ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( ( *pHeader ) & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+ {
+ LogError( ( "Header is not publish packet header" ) );
+ status = MQTTBadParameter;
+ }
+ else if( set == true )
+ {
+ UINT8_SET_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+ }
+ else
+ {
+ UINT8_CLEAR_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
+ const size_t * pIndex,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pIncomingPacket == NULL )
+ {
+ LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pIndex == NULL )
+ {
+ LogError( ( "Invalid parameter: pIndex is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( pBuffer == NULL )
+ {
+ LogError( ( "Invalid parameter: pBuffer is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ /* There should be at least one byte in the buffer */
+ else if( *pIndex < 1U )
+ {
+ /* No data is available. There are 0 bytes received from the network
+ * receive function. */
+ status = MQTTNoDataAvailable;
+ }
+ else
+ {
+ /* At least one byte is present which should be deciphered. */
+ pIncomingPacket->type = pBuffer[ 0 ];
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Check validity. */
+ if( incomingPacketValid( pIncomingPacket->type ) == true )
+ {
+ LogTrace( ( "Incoming packet type: %s",
+ MQTT_GetPacketTypeString( pIncomingPacket->type ) ) );
+ status = processRemainingLength( pBuffer,
+ pIndex,
+ pIncomingPacket );
+ }
+ else
+ {
+ LogError( ( "Incoming packet invalid: Packet type=%u.",
+ ( unsigned int ) pIncomingPacket->type ) );
+ status = MQTTBadResponse;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_InitConnect( MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( pConnectProperties == NULL )
+ {
+ LogError( ( "pConnectProperties cannot be NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ pConnectProperties->receiveMax = UINT16_MAX;
+ pConnectProperties->maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ pConnectProperties->requestProblemInfo = true;
+ pConnectProperties->serverReceiveMax = UINT16_MAX;
+ pConnectProperties->serverMaxQos = 2U;
+ pConnectProperties->serverMaxPacketSize = MQTT_MAX_PACKET_SIZE;
+ pConnectProperties->isWildcardAvailable = 1U;
+ pConnectProperties->isSubscriptionIdAvailable = 1U;
+ pConnectProperties->isSharedAvailable = 1U;
+ pConnectProperties->sessionExpiry = 0U;
+ pConnectProperties->topicAliasMax = 0U;
+ pConnectProperties->requestResponseInfo = false;
+ pConnectProperties->retainAvailable = 1U;
+ pConnectProperties->serverTopicAliasMax = 0U;
+ pConnectProperties->serverKeepAlive = UINT16_MAX;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTTPropertyBuilder_Init( MQTTPropBuilder_t * pPropertyBuilder,
+ uint8_t * buffer,
+ size_t length )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ if( ( pPropertyBuilder == NULL ) || ( buffer == NULL ) || ( length == 0U ) )
+ {
+ LogError( ( "Invalid arguments passed to MQTTPropertyBuilder_Init. "
+ "pPropertyBuilder must be non-NULL; "
+ "buffer must be non-NULL; "
+ "and length must be non-zero. " ) );
+ status = MQTTBadParameter;
+ }
+ else if( length >= MQTT_REMAINING_LENGTH_INVALID )
+ {
+ LogError( ( "The length must be less than max MQTT packet size (268435456)." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ /* Nothing to do. All values are valid. */
+ }
+
+ if( status == MQTTSuccess )
+ {
+ pPropertyBuilder->pBuffer = buffer;
+ pPropertyBuilder->currentIndex = 0;
+ pPropertyBuilder->bufferLength = length;
+ pPropertyBuilder->fieldSet = 0; /* 0 means no field is set. */
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ValidateWillProperties( const MQTTPropBuilder_t * pPropertyBuilder )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex = NULL;
+ uint32_t propertyBitMask = 0;
+
+ if( ( pPropertyBuilder == NULL ) || ( pPropertyBuilder->pBuffer == NULL ) )
+ {
+ status = MQTTBadParameter;
+ }
+ else if( ( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ) ||
+ ( pPropertyBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) )
+ {
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pPropertyBuilder->currentIndex;
+ pIndex = pPropertyBuilder->pBuffer;
+ }
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pIndex;
+ bool used = false;
+ const char * data;
+ size_t dataLength;
+
+ pIndex = &pIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_WILL_DELAY_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_WILL_DELAY_POS ) != true )
+ {
+ status = decodeUint32t( NULL, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_WILL_DELAY_POS );
+ }
+ else
+ {
+ LogError( ( "Will Delay Interval included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_PAYLOAD_FORMAT_ID:
+ {
+ uint8_t property;
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_PAYLOAD_FORMAT_INDICATOR_POS ) != true )
+ {
+ status = decodeUint8t( &property, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_PAYLOAD_FORMAT_INDICATOR_POS );
+ }
+ else
+ {
+ LogError( ( "Payload format indicator included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( ( property != 0 ) && ( property != 1 ) )
+ {
+ LogError( ( "Payload Format can only be 0 or 1 in will properties." ) );
+ status = MQTTBadResponse;
+ }
+ }
+ }
+ break;
+
+ case MQTT_MSG_EXPIRY_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_MESSAGE_EXPIRY_INTERVAL_POS ) != true )
+ {
+ status = decodeUint32t( NULL, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_MESSAGE_EXPIRY_INTERVAL_POS );
+ }
+ else
+ {
+ LogError( ( "Message Expiry Interval included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_CONTENT_TYPE_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_CONTENT_TYPE_POS ) != true )
+ {
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_CONTENT_TYPE_POS );
+ }
+ else
+ {
+ LogError( ( "Content Type included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_RESPONSE_TOPIC_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_RESPONSE_TOPIC_POS ) != true )
+ {
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_RESPONSE_TOPIC_POS );
+ }
+ else
+ {
+ LogError( ( "Response topic included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_CORRELATION_DATA_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_CORRELATION_DATA_POS ) != true )
+ {
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_CORRELATION_DATA_POS );
+ }
+ else
+ {
+ LogError( ( "Corelation Data included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key,
+ &keyLength,
+ &value,
+ &valueLength,
+ &propertyLength,
+ &pIndex );
+ }
+ break;
+
+ default:
+ status = MQTTBadResponse;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ValidateConnectProperties( const MQTTPropBuilder_t * pPropertyBuilder,
+ bool * isRequestProblemInfoSet,
+ uint32_t * pPacketMaxSizeValue )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex = NULL;
+ uint32_t propertyBitMask = 0;
+
+ if( ( pPropertyBuilder == NULL ) ||
+ ( pPropertyBuilder->pBuffer == NULL ) ||
+ ( isRequestProblemInfoSet == NULL ) )
+ {
+ status = MQTTBadParameter;
+ }
+ else if( ( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ) ||
+ ( pPropertyBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) )
+ {
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = pPropertyBuilder->currentIndex;
+ pIndex = pPropertyBuilder->pBuffer;
+ *isRequestProblemInfoSet = false;
+ }
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pIndex;
+ bool used = false;
+ const char * data;
+ size_t dataLength;
+
+ pIndex = &pIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_SESSION_EXPIRY_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_SESSION_EXPIRY_INTERVAL_POS ) != true )
+ {
+ status = decodeUint32t( NULL, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ }
+ else
+ {
+ LogError( ( "Session Expiry Interval included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_RECEIVE_MAX_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_RECEIVE_MAXIMUM_POS ) != true )
+ {
+ uint16_t receiveMax;
+ status = decodeUint16t( &receiveMax, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_RECEIVE_MAXIMUM_POS );
+
+ if( status == MQTTSuccess )
+ {
+ if( receiveMax == 0U )
+ {
+ LogError( ( "Receive Maximum cannot be 0 in CONNECT properties." ) );
+ status = MQTTBadResponse;
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Receive Maximum included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_MAX_PACKET_SIZE_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_MAX_PACKET_SIZE_POS ) != true )
+ {
+ uint32_t maxPacketSize;
+ status = decodeUint32t( &maxPacketSize, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_MAX_PACKET_SIZE_POS );
+
+ if( status == MQTTSuccess )
+ {
+ if( maxPacketSize == 0U )
+ {
+ LogError( ( "Maximum Packet Size cannot be 0 in CONNECT properties." ) );
+ status = MQTTBadResponse;
+ }
+ else if( pPacketMaxSizeValue != NULL )
+ {
+ *pPacketMaxSizeValue = maxPacketSize;
+ }
+ else
+ {
+ /* Nothing to do. */
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Maximum Packet Size included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_TOPIC_ALIAS_MAX_POS ) != true )
+ {
+ status = decodeUint16t( NULL, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_TOPIC_ALIAS_MAX_POS );
+ }
+ else
+ {
+ LogError( ( "Topic Alias Maximum included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_REQUEST_RESPONSE_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_REQUEST_RESPONSE_INFO_POS ) != true )
+ {
+ uint8_t requestResponseInfo;
+ status = decodeUint8t( &requestResponseInfo, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_REQUEST_RESPONSE_INFO_POS );
+
+ if( status == MQTTSuccess )
+ {
+ if( ( requestResponseInfo != 0U ) && ( requestResponseInfo != 1U ) )
+ {
+ LogError( ( "Request Response Information can only be 0 or 1 in CONNECT properties." ) );
+ status = MQTTBadResponse;
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Request Response Information included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_REQUEST_PROBLEM_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_REQUEST_PROBLEM_INFO_POS ) != true )
+ {
+ uint8_t requestProblemInfo;
+ status = decodeUint8t( &requestProblemInfo, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_REQUEST_PROBLEM_INFO_POS );
+
+ if( status == MQTTSuccess )
+ {
+ if( ( requestProblemInfo != 0U ) && ( requestProblemInfo != 1U ) )
+ {
+ LogError( ( "Request Problem Information can only be 0 or 1 in CONNECT properties." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ *isRequestProblemInfoSet = ( requestProblemInfo == 1U );
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Request Problem Information included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_AUTH_METHOD_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_AUTHENTICATION_METHOD_POS ) != true )
+ {
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_AUTHENTICATION_METHOD_POS );
+ }
+ else
+ {
+ LogError( ( "Authentication Method included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_AUTH_DATA_ID:
+
+ if( UINT32_CHECK_BIT( propertyBitMask, MQTT_AUTHENTICATION_DATA_POS ) != true )
+ {
+ status = decodeUtf8( &data, &dataLength, &propertyLength, &used, &pIndex );
+ UINT32_SET_BIT( propertyBitMask, MQTT_AUTHENTICATION_DATA_POS );
+ }
+ else
+ {
+ LogError( ( "Authentication Data included more than once in the properties." ) );
+ status = MQTTBadResponse;
+ }
+
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key,
+ &keyLength,
+ &value,
+ &valueLength,
+ &propertyLength,
+ &pIndex );
+ }
+ break;
+
+ default:
+ LogError( ( "Invalid property ID 0x%02x in CONNECT properties.", propertyId ) );
+ status = MQTTBadResponse;
+ break;
+ }
+ }
+
+ if( status == MQTTSuccess )
+ {
+ if( ( UINT32_CHECK_BIT( propertyBitMask, MQTT_AUTHENTICATION_DATA_POS ) == true ) &&
+ ( UINT32_CHECK_BIT( propertyBitMask, MQTT_AUTHENTICATION_METHOD_POS ) != true ) )
+ {
+ LogError( ( "Authentication data added but no authentication method present in CONNECT properties." ) );
+ status = MQTTBadParameter;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ValidateSubscribeProperties( bool isSubscriptionIdAvailable,
+ const MQTTPropBuilder_t * propBuilder )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pLocalIndex = NULL;
+ uint32_t subscriptionId = 0;
+ bool subscriptionIDIncluded = false;
+
+ if( ( propBuilder == NULL ) || ( propBuilder->pBuffer == NULL ) )
+ {
+ status = MQTTBadParameter;
+ }
+ else if( ( CHECK_SIZE_T_OVERFLOWS_32BIT( propBuilder->currentIndex ) ) ||
+ ( propBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) )
+ {
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = propBuilder->currentIndex;
+ pLocalIndex = propBuilder->pBuffer;
+ }
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ uint8_t propertyId = *pLocalIndex;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_SUBSCRIPTION_ID_ID:
+
+ if( subscriptionIDIncluded == true )
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Subscription ID included. Protocol Error to include twice." ) );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ status = decodeVariableLength( pLocalIndex, propertyLength, &subscriptionId );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ propertyLength -= variableLengthEncodedSize( subscriptionId );
+
+ if( isSubscriptionIdAvailable == false )
+ {
+ LogError( ( "Protocol Error : Subscription Id not available" ) );
+ status = MQTTBadParameter;
+ }
+ else if( subscriptionId == 0 )
+ {
+ LogError( ( "Protocol Error : Subscription Id value set to 0" ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ subscriptionIDIncluded = true;
+ LogTrace( ( "Processing subscription ID %" PRIu32,
+ subscriptionId ) );
+ }
+ }
+
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key, &keyLength, &value, &valueLength, &propertyLength, &pLocalIndex );
+
+ if( status == MQTTSuccess )
+ {
+ LogTrace( ( "Processing User Property %.*s:%.*s",
+ ( int ) keyLength, key,
+ ( int ) valueLength, value ) );
+ }
+ }
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t MQTT_ValidatePublishProperties( uint16_t serverTopicAliasMax,
+ const MQTTPropBuilder_t * propBuilder,
+ uint16_t * topicAlias )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pLocalIndex = NULL;
+ bool topicAliasBool = false;
- if( pFixedBuffer == NULL )
+ if( ( propBuilder == NULL ) || ( propBuilder->pBuffer == NULL ) )
{
- LogError( ( "pFixedBuffer is NULL." ) );
+ LogError( ( "Property Builder is NULL." ) );
status = MQTTBadParameter;
}
- else if( pFixedBuffer->pBuffer == NULL )
+ else if( topicAlias == NULL )
{
- LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
+ LogError( ( "Topic Alias is NULL." ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( CHECK_SIZE_T_OVERFLOWS_32BIT( propBuilder->currentIndex ) ) ||
+ ( propBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) )
+ {
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
status = MQTTBadParameter;
}
else
{
- /* Empty else MISRA 15.7 */
+ propertyLength = propBuilder->currentIndex;
+ pLocalIndex = propBuilder->pBuffer;
}
- if( status == MQTTSuccess )
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
{
- if( pFixedBuffer->size < MQTT_PACKET_PINGREQ_SIZE )
+ uint8_t propertyId = *pLocalIndex;
+ bool used = false;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
{
- LogError( ( "Buffer size of %lu is not sufficient to hold "
- "serialized PINGREQ packet of size of %lu.",
- ( unsigned long ) pFixedBuffer->size,
- MQTT_PACKET_PINGREQ_SIZE ) );
- status = MQTTNoMemory;
- }
- }
+ case MQTT_PAYLOAD_FORMAT_ID:
+ {
+ uint8_t property;
+ status = decodeUint8t( &property, &propertyLength, &used, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_MSG_EXPIRY_ID:
+ {
+ uint32_t property;
+ status = decodeUint32t( &property, &propertyLength, &used, &pLocalIndex );
+ break;
+ }
+
+ case MQTT_CONTENT_TYPE_ID:
+ case MQTT_CORRELATION_DATA_ID:
+ case MQTT_RESPONSE_TOPIC_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &used, &pLocalIndex );
+ break;
+ }
+
+ case MQTT_TOPIC_ALIAS_ID:
+ status = decodeUint16t( topicAlias, &propertyLength, &topicAliasBool, &pLocalIndex );
+
+ if( ( status == MQTTSuccess ) && ( serverTopicAliasMax < *topicAlias ) )
+ {
+ LogError( ( "Protocol Error: Topic Alias greater than Topic Alias Max" ) );
+ status = MQTTBadParameter;
+ }
- if( status == MQTTSuccess )
- {
- /* Ping request packets are always the same. */
- pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_PINGREQ;
- pFixedBuffer->pBuffer[ 1 ] = 0x00;
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * pPropertyKey;
+ size_t propertyKeyLen;
+ const char * pPropertyValue;
+ size_t propertyValueLen;
+ status = decodeUserProp( &pPropertyKey,
+ &propertyKeyLen,
+ &pPropertyValue,
+ &propertyValueLen,
+ &propertyLength,
+ &pLocalIndex );
+ }
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ break;
+ }
}
return status;
@@ -2446,36 +5378,60 @@ MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer )
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
- uint16_t * pPacketId,
- MQTTPublishInfo_t * pPublishInfo )
+MQTTStatus_t MQTT_ValidatePublishParams( const MQTTPublishInfo_t * pPublishInfo,
+ uint8_t retainAvailable,
+ uint8_t maxQos,
+ uint16_t topicAlias,
+ uint32_t maxPacketSize )
{
- MQTTStatus_t status = MQTTSuccess;
+ MQTTStatus_t status;
- if( ( pIncomingPacket == NULL ) || ( pPacketId == NULL ) || ( pPublishInfo == NULL ) )
+ if( pPublishInfo == NULL )
{
- LogError( ( "Argument cannot be NULL: pIncomingPacket=%p, "
- "pPacketId=%p, pPublishInfo=%p",
- ( void * ) pIncomingPacket,
- ( void * ) pPacketId,
- ( void * ) pPublishInfo ) );
+ LogError( ( "Argument cannot be NULL: pPublishInfo=%p ",
+ ( void * ) pPublishInfo
+ ) );
status = MQTTBadParameter;
}
- else if( ( pIncomingPacket->type & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+ else if( ( pPublishInfo->retain == true ) && ( retainAvailable == 0U ) )
{
- LogError( ( "Packet is not publish. Packet type: %02x.",
- ( unsigned int ) pIncomingPacket->type ) );
+ LogError( ( "Retain is not available." ) );
status = MQTTBadParameter;
}
- else if( pIncomingPacket->pRemainingData == NULL )
+ else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( maxQos == 0U ) )
+ {
+ LogError( ( "Qos value = %hu is not allowed by the server ",
+ ( unsigned short ) pPublishInfo->qos ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( topicAlias == 0U ) && ( pPublishInfo->topicNameLength == 0U ) )
+ {
+ LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
+ "topicNameLength=%hu.",
+ ( void * ) pPublishInfo->pTopicName,
+ ( unsigned short ) pPublishInfo->topicNameLength ) );
+ status = MQTTBadParameter;
+ }
+ else if( ( pPublishInfo->pTopicName == NULL ) && ( pPublishInfo->topicNameLength != 0U ) )
+ {
+ LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
+ "topicNameLength=%hu.",
+ ( void * ) pPublishInfo->pTopicName,
+ ( unsigned short ) pPublishInfo->topicNameLength ) );
+ status = MQTTBadParameter;
+ }
+ else if( CHECK_SIZE_T_OVERFLOWS_16BIT( pPublishInfo->topicNameLength ) )
+ {
+ LogError( ( "topicNameLength must be less than 65535 to fit in 16-bits." ) );
+ status = MQTTBadParameter;
+ }
+ else if( maxPacketSize == 0U )
{
- LogError( ( "Argument cannot be NULL: "
- "pIncomingPacket->pRemainingData is NULL." ) );
status = MQTTBadParameter;
}
else
{
- status = deserializePublish( pIncomingPacket, pPacketId, pPublishInfo );
+ status = MQTTSuccess;
}
return status;
@@ -2483,74 +5439,58 @@ MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
- uint16_t * pPacketId,
- bool * pSessionPresent )
+MQTTStatus_t MQTT_ValidatePublishAckProperties( const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex = NULL;
+ bool used = false;
- if( pIncomingPacket == NULL )
+ if( ( pPropertyBuilder != NULL ) &&
+ ( ( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ) ||
+ ( pPropertyBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) ) )
{
- LogError( ( "pIncomingPacket cannot be NULL." ) );
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
status = MQTTBadParameter;
}
- /* Pointer for packet identifier cannot be NULL for packets other than
- * CONNACK and PINGRESP. */
- else if( ( pPacketId == NULL ) &&
- ( ( pIncomingPacket->type != MQTT_PACKET_TYPE_CONNACK ) &&
- ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) ) )
- {
- LogError( ( "pPacketId cannot be NULL for packet type %02x.",
- ( unsigned int ) pIncomingPacket->type ) );
- status = MQTTBadParameter;
- }
- /* Pointer for session present cannot be NULL for CONNACK. */
- else if( ( pSessionPresent == NULL ) &&
- ( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK ) )
+ if( ( status == MQTTSuccess ) && ( pPropertyBuilder != NULL ) && ( pPropertyBuilder->pBuffer != NULL ) )
{
- LogError( ( "pSessionPresent cannot be NULL for CONNACK packet." ) );
- status = MQTTBadParameter;
+ propertyLength = pPropertyBuilder->currentIndex;
+ pIndex = pPropertyBuilder->pBuffer;
}
- /* Pointer for remaining data cannot be NULL for packets other
- * than PINGRESP. */
- else if( ( pIncomingPacket->pRemainingData == NULL ) &&
- ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
- {
- LogError( ( "Remaining data of incoming packet is NULL." ) );
- status = MQTTBadParameter;
- }
- else
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
{
- /* Make sure response packet is a valid ack. */
- switch( pIncomingPacket->type )
- {
- case MQTT_PACKET_TYPE_CONNACK:
- status = deserializeConnack( pIncomingPacket, pSessionPresent );
- break;
-
- case MQTT_PACKET_TYPE_SUBACK:
- status = deserializeSuback( pIncomingPacket, pPacketId );
- break;
-
- case MQTT_PACKET_TYPE_PINGRESP:
- status = deserializePingresp( pIncomingPacket );
- break;
+ uint8_t propertyId = *pIndex;
+ pIndex = &pIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
- case MQTT_PACKET_TYPE_UNSUBACK:
- case MQTT_PACKET_TYPE_PUBACK:
- case MQTT_PACKET_TYPE_PUBREC:
- case MQTT_PACKET_TYPE_PUBREL:
- case MQTT_PACKET_TYPE_PUBCOMP:
- status = deserializeSimpleAck( pIncomingPacket, pPacketId );
- break;
+ switch( propertyId )
+ {
+ case MQTT_REASON_STRING_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &used, &pIndex );
+ }
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key,
+ &keyLength,
+ &value,
+ &valueLength,
+ &propertyLength,
+ &pIndex );
+ }
+ break;
- /* Any other packet type is invalid. */
default:
- LogError( ( "IotMqtt_DeserializeResponse() called with unknown packet type:(%02x).",
- ( unsigned int ) pIncomingPacket->type ) );
- status = MQTTBadResponse;
+ status = MQTTBadParameter;
break;
}
}
@@ -2560,64 +5500,68 @@ MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
- NetworkContext_t * pNetworkContext,
- MQTTPacketInfo_t * pIncomingPacket )
+MQTTStatus_t MQTT_GetAckPacketSize( uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ size_t ackPropertyLength )
{
MQTTStatus_t status = MQTTSuccess;
- int32_t bytesReceived = 0;
+ size_t length = 0U;
+ uint32_t propertyLength;
+ uint32_t packetSize = 0U;
- if( pIncomingPacket == NULL )
+ /* Validate the parameters. */
+ if( ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
{
- LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+ LogError( ( "pRemainingLength and pPacketSize cannot be NULL." ) );
status = MQTTBadParameter;
}
- else
+ else if( maxPacketSize == 0U )
{
- /* Read a single byte. */
- bytesReceived = readFunc( pNetworkContext,
- &( pIncomingPacket->type ),
- 1U );
+ LogError( ( "maxPacketSize cannot be 0 as specified by MQTT spec." ) );
+ status = MQTTBadParameter;
}
-
- if( bytesReceived == 1 )
+ else if( CHECK_SIZE_T_OVERFLOWS_32BIT( ackPropertyLength ) ||
+ ( ackPropertyLength > MQTT_MAX_REMAINING_LENGTH ) )
{
- /* Check validity. */
- if( incomingPacketValid( pIncomingPacket->type ) == true )
- {
- pIncomingPacket->remainingLength = getRemainingLength( readFunc,
- pNetworkContext );
+ LogError( ( "ackPropertyLength must be smaller than 268435455 to fit in MQTT packet." ) );
+ status = MQTTBadParameter;
+ }
+ else
+ {
+ propertyLength = ackPropertyLength;
- if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )
- {
- LogError( ( "Incoming packet remaining length invalid." ) );
- status = MQTTBadResponse;
- }
+ /* 1 byte Reason code + 2 byte Packet Identifier. */
+ length += 3U;
+
+ length += variableLengthEncodedSize( propertyLength ) + propertyLength;
+
+ if( length > MQTT_MAX_REMAINING_LENGTH )
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Remaining Length greater than Maximum Remaining Length according to MQTTv5 spec." ) );
}
else
{
- LogError( ( "Incoming packet invalid: Packet type=%u.",
- ( unsigned int ) pIncomingPacket->type ) );
- status = MQTTBadResponse;
+ *pRemainingLength = length;
}
}
- else if( ( status != MQTTBadParameter ) && ( bytesReceived == 0 ) )
- {
- status = MQTTNoDataAvailable;
- }
- /* If the input packet was valid, then any other number of bytes received is
- * a failure. */
- else if( status != MQTTBadParameter )
- {
- LogError( ( "A single byte was not read from the transport: "
- "transportStatus=%ld.",
- ( long int ) bytesReceived ) );
- status = MQTTRecvFailed;
- }
- else
+ if( status == MQTTSuccess )
{
- /* Empty else MISRA 15.7 */
+ /* Length of variable header + 1 byte ACK header +
+ * bytes required to encode the remaining length. */
+ packetSize = length + 1U + variableLengthEncodedSize( length );
+
+ if( packetSize > maxPacketSize )
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Packet size greater than Max Packet Size specified in the CONNACK" ) );
+ }
+ else
+ {
+ *pPacketSize = packetSize;
+ }
}
return status;
@@ -2625,28 +5569,74 @@ MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader,
- bool set )
+MQTTStatus_t MQTT_ValidateDisconnectProperties( uint32_t connectSessionExpiry,
+ const MQTTPropBuilder_t * pPropertyBuilder )
{
MQTTStatus_t status = MQTTSuccess;
+ uint32_t propertyLength = 0U;
+ uint8_t * pIndex = NULL;
+ uint32_t sessionExpiry;
- if( pHeader == NULL )
+ if( ( pPropertyBuilder == NULL ) || ( pPropertyBuilder->pBuffer == NULL ) )
{
- LogError( ( "Header cannot be NULL" ) );
+ LogError( ( "Arguments cannot be NULL : pPropertyBuilder=%p.", ( void * ) pPropertyBuilder ) );
status = MQTTBadParameter;
}
- else if( ( ( *pHeader ) & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
+ else if( ( CHECK_SIZE_T_OVERFLOWS_32BIT( pPropertyBuilder->currentIndex ) ) ||
+ ( pPropertyBuilder->currentIndex >= MQTT_REMAINING_LENGTH_INVALID ) )
{
- LogError( ( "Header is not publish packet header" ) );
+ LogError( ( "Property length cannot have more than %" PRIu32 " bytes", MQTT_REMAINING_LENGTH_INVALID ) );
status = MQTTBadParameter;
}
- else if( set == true )
+ else
{
- UINT8_SET_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+ propertyLength = pPropertyBuilder->currentIndex;
+ pIndex = pPropertyBuilder->pBuffer;
}
- else
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
{
- UINT8_CLEAR_BIT( *pHeader, MQTT_PUBLISH_FLAG_DUP );
+ uint8_t propertyId = *pIndex;
+ bool used = false;
+ pIndex = &pIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ switch( propertyId )
+ {
+ case MQTT_SESSION_EXPIRY_ID:
+ status = decodeUint32t( &sessionExpiry, &propertyLength, &used, &pIndex );
+
+ if( status == MQTTSuccess )
+ {
+ if( ( connectSessionExpiry == 0U ) && ( sessionExpiry != 0U ) )
+ {
+ status = MQTTBadParameter;
+ LogError( ( "Disconnect Session Expiry non-zero while Connect Session Expiry was zero. " ) );
+ }
+ }
+
+ break;
+
+ case MQTT_REASON_STRING_ID:
+ {
+ const char * pProperty;
+ size_t length;
+ status = decodeUtf8( &pProperty, &length, &propertyLength, &used, &pIndex );
+ }
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key, &keyLength, &value, &valueLength, &propertyLength, &pIndex );
+ }
+ break;
+
+ default:
+ status = MQTTBadParameter;
+ break;
+ }
}
return status;
@@ -2654,54 +5644,159 @@ MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader,
/*-----------------------------------------------------------*/
-MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
- const size_t * pIndex,
- MQTTPacketInfo_t * pIncomingPacket )
+MQTTStatus_t MQTT_DeserializeDisconnect( const MQTTPacketInfo_t * pPacket,
+ uint32_t maxPacketSize,
+ MQTTReasonCodeInfo_t * pDisconnectInfo,
+ MQTTPropBuilder_t * pPropBuffer )
{
MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pIndex = NULL;
+ uint32_t propertyLength = 0U;
- if( pIncomingPacket == NULL )
+ /* Validate the arguments. */
+ if( ( pPacket == NULL ) || ( pPacket->pRemainingData == NULL ) )
{
- LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
+ LogError( ( "pPacket and pPacket->pRemainingData must not be NULL." ) );
status = MQTTBadParameter;
}
- else if( pIndex == NULL )
+ else if( pDisconnectInfo == NULL )
{
- LogError( ( "Invalid parameter: pIndex is NULL." ) );
+ LogError( ( "pDisconnectInfo must not be NULL." ) );
status = MQTTBadParameter;
}
- else if( pBuffer == NULL )
+ else if( maxPacketSize == 0U )
{
- LogError( ( "Invalid parameter: pBuffer is NULL." ) );
+ LogError( ( "maxPacketSize must not be 0." ) );
status = MQTTBadParameter;
}
- /* There should be at least one byte in the buffer */
- else if( *pIndex < 1U )
+ else if( pPacket->remainingLength >= MQTT_REMAINING_LENGTH_INVALID )
{
- /* No data is available. There are 0 bytes received from the network
- * receive function. */
- status = MQTTNoDataAvailable;
+ LogError( ( "pPacket->remainingLength must be less than 268435456." ) );
+ status = MQTTBadResponse;
+ }
+
+ /* Packet size should not be more than the max allowed by the client.
+ * The length is calculated as: Remaining length +
+ * Bytes required to encode the remaining length +
+ * The disconnect header of 1 byte.
+ */
+ else if( ( pPacket->remainingLength + variableLengthEncodedSize( pPacket->remainingLength ) + 1U ) > maxPacketSize )
+ {
+ status = MQTTBadResponse;
+ }
+ else if( pPacket->remainingLength == 0U )
+ {
+ /* No properties or reason code provided. Nothing to do. */
}
else
{
- /* At least one byte is present which should be deciphered. */
- pIncomingPacket->type = pBuffer[ 0 ];
+ /* Extract the reason code. */
+ pIndex = pPacket->pRemainingData;
+ pDisconnectInfo->reasonCode = pIndex;
+ pDisconnectInfo->reasonCodeLength = 1U;
+ pIndex++;
+
+ /* Validate the reason code. */
+ status = validateDisconnectResponse( *pDisconnectInfo->reasonCode, true );
}
if( status == MQTTSuccess )
{
- /* Check validity. */
- if( incomingPacketValid( pIncomingPacket->type ) == true )
+ if( ( pPacket->remainingLength > 1U ) )
{
- status = processRemainingLength( pBuffer,
- pIndex,
- pIncomingPacket );
+ /* Extract the property length. */
+ status = decodeVariableLength( pIndex, pPacket->remainingLength - 1U, &propertyLength );
+
+ if( status == MQTTSuccess )
+ {
+ /* Validate the remaining length. It must only have the reason code
+ * and the properties and the bytes needed to encode the property length. */
+ if( pPacket->remainingLength != ( propertyLength + variableLengthEncodedSize( propertyLength ) + 1U ) )
+ {
+ LogError( ( "Remaining length doesn't match the expected size." ) );
+ status = MQTTBadResponse;
+ }
+ else if( CHECK_U32T_OVERFLOWS_SIZE_T( propertyLength ) )
+ {
+ LogError( ( "Incoming property length will overflow the property buffer." ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ pIndex = &pIndex[ variableLengthEncodedSize( propertyLength ) ];
+
+ if( pPropBuffer != NULL )
+ {
+ pPropBuffer->bufferLength = propertyLength;
+ pPropBuffer->pBuffer = pIndex;
+ }
+ }
+ }
+ else
+ {
+ LogError( ( "Failed to decode the property length. Malformed packet." ) );
+ status = MQTTBadResponse;
+ }
}
- else
+ }
+
+ if( status == MQTTSuccess )
+ {
+ status = validateIncomingDisconnectProperties( pIndex, propertyLength );
+
+ if( status != MQTTSuccess )
{
- LogError( ( "Incoming packet invalid: Packet type=%u.",
- ( unsigned int ) pIncomingPacket->type ) );
- status = MQTTBadResponse;
+ LogError( ( "Failed to validate disconnect properties." ) );
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+static MQTTStatus_t validateIncomingDisconnectProperties( uint8_t * pIndex,
+ uint32_t disconnectPropertyLength )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t * pLocalIndex = pIndex;
+ const char * pReasonString;
+ size_t reasonStringLength;
+ const char * pServerRef;
+ size_t pServerRefLength;
+ uint32_t propertyLength = disconnectPropertyLength;
+ bool reasonString = false;
+ bool serverRef = false;
+
+ while( ( propertyLength > 0U ) && ( status == MQTTSuccess ) )
+ {
+ /* Decode the property id. */
+ uint8_t propertyId = *pLocalIndex;
+ pLocalIndex = &pLocalIndex[ 1 ];
+ propertyLength -= sizeof( uint8_t );
+
+ /* Validate the property id and decode accordingly. */
+ switch( propertyId )
+ {
+ case MQTT_REASON_STRING_ID:
+ status = decodeUtf8( &pReasonString, &reasonStringLength, &propertyLength, &reasonString, &pLocalIndex );
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ {
+ const char * key, * value;
+ size_t keyLength, valueLength;
+ status = decodeUserProp( &key, &keyLength, &value, &valueLength, &propertyLength, &pLocalIndex );
+ }
+ break;
+
+ case MQTT_SERVER_REF_ID:
+ status = decodeUtf8( &pServerRef, &pServerRefLength, &propertyLength, &serverRef, &pLocalIndex );
+ break;
+
+ default:
+ status = MQTTBadResponse;
+ break;
}
}
diff --git a/source/core_mqtt_serializer_private.c b/source/core_mqtt_serializer_private.c
new file mode 100644
index 000000000..d7ec635b4
--- /dev/null
+++ b/source/core_mqtt_serializer_private.c
@@ -0,0 +1,643 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_serializer_private.c
+ * @brief Implements private functions used by serializer and deserializer.
+ * DO NOT use these functions in your application.
+ *
+ * @note These functions should not be called by the application or relied upon
+ * since their implementation can change. These are for internal use by the
+ * library only.
+ */
+#include
+#include
+#include
+#include
+
+#include "core_mqtt_serializer.h"
+#include "private/core_mqtt_serializer_private.h"
+
+/* Include config defaults header to get default values of configs. */
+#include "core_mqtt_config_defaults.h"
+
+/**
+ * @brief Version 5 has the value 5.
+ */
+#define MQTT_VERSION_5 ( 5U )
+
+/*-----------------------------------------------------------*/
+
+size_t variableLengthEncodedSize( uint32_t length )
+{
+ size_t encodedSize;
+
+ /* Determine how many bytes are needed to encode length.
+ * The values below are taken from the MQTT 5.0 spec. */
+
+ /* 1 byte is needed to encode lengths between 0 and 127. */
+ if( length < 128U )
+ {
+ encodedSize = 1U;
+ }
+ /* 2 bytes are needed to encode lengths between 128 and 16,383. */
+ else if( length < 16384U )
+ {
+ encodedSize = 2U;
+ }
+ /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */
+ else if( length < 2097152U )
+ {
+ encodedSize = 3U;
+ }
+ /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */
+ else
+ {
+ encodedSize = 4U;
+ }
+
+ LogDebug( ( "Encoded size for length %lu is %lu bytes.",
+ ( unsigned long ) length,
+ ( unsigned long ) encodedSize ) );
+
+ return encodedSize;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * encodeString( uint8_t * pDestination,
+ const char * pSource,
+ uint16_t sourceLength )
+{
+ uint8_t * pBuffer = NULL;
+
+ assert( pDestination != NULL );
+
+ pBuffer = pDestination;
+
+ /* The first byte of a UTF-8 string is the high byte of the string length. */
+ *pBuffer = UINT16_HIGH_BYTE( sourceLength );
+ pBuffer++;
+
+ /* The second byte of a UTF-8 string is the low byte of the string length. */
+ *pBuffer = UINT16_LOW_BYTE( sourceLength );
+ pBuffer++;
+
+ /* Copy the string into pBuffer. */
+ if( pSource != NULL )
+ {
+ ( void ) memcpy( ( void * ) pBuffer, ( const void * ) pSource, sourceLength );
+ }
+
+ /* Return the pointer to the end of the encoded string. */
+ pBuffer = &pBuffer[ sourceLength ];
+
+ return pBuffer;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUserProp( const char ** pPropertyKey,
+ size_t * pPropertyKeyLen,
+ const char ** pPropertyValue,
+ size_t * pPropertyValueLen,
+ uint32_t * pPropertyLength,
+ uint8_t ** pIndex )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ const char * pKey = NULL;
+ const char * pValue = NULL;
+ size_t keyLength = 0U;
+ size_t valueLength = 0U;
+ bool used = false;
+
+ assert( pIndex != NULL );
+ assert( pPropertyLength != NULL );
+
+ /* Decode the user property key using decodeUtf8. */
+ status = decodeUtf8( &pKey, &keyLength, pPropertyLength, &used, pIndex );
+
+ if( status == MQTTSuccess )
+ {
+ used = false;
+ /* Decode the user property value using decodeUtf8. */
+ status = decodeUtf8( &pValue, &valueLength, pPropertyLength, &used, pIndex );
+ }
+
+ if( status == MQTTSuccess )
+ {
+ /* Store the decoded key and value. */
+ *pPropertyKey = pKey;
+ *pPropertyKeyLen = keyLength;
+ *pPropertyValue = pValue;
+ *pPropertyValueLen = valueLength;
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint32t( uint32_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ uint8_t * pLocalIndex = *pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( pIndex != NULL );
+ assert( pPropertyLength != NULL );
+ assert( pUsed != NULL );
+
+ /* Protocol error to include the same property twice. */
+ if( *pUsed == true )
+ {
+ status = MQTTBadResponse;
+ }
+ /* Validate the length and decode. */
+ else if( *pPropertyLength < sizeof( uint32_t ) )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ if( pProperty != NULL )
+ {
+ *pProperty = UINT32_DECODE( pLocalIndex );
+ }
+
+ pLocalIndex = &pLocalIndex[ sizeof( uint32_t ) ];
+ *pUsed = true;
+ *pPropertyLength -= sizeof( uint32_t );
+ }
+
+ *pIndex = pLocalIndex;
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint16t( uint16_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ uint8_t * pLocalIndex = *pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( pIndex != NULL );
+ assert( pPropertyLength != NULL );
+ assert( pUsed != NULL );
+
+ /* Protocol error to include the same property twice. */
+ if( *pUsed == true )
+ {
+ status = MQTTBadResponse;
+ }
+ /* Validate the length and decode. */
+ else if( *pPropertyLength < sizeof( uint16_t ) )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ if( pProperty != NULL )
+ {
+ *pProperty = UINT16_DECODE( pLocalIndex );
+ }
+
+ pLocalIndex = &pLocalIndex[ sizeof( uint16_t ) ];
+ *pUsed = true;
+ *pPropertyLength -= sizeof( uint16_t );
+ }
+
+ *pIndex = pLocalIndex;
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint8t( uint8_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ uint8_t * pLocalIndex = *pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( pIndex != NULL );
+ assert( pPropertyLength != NULL );
+ assert( pUsed != NULL );
+
+ /* Protocol error to include the same property twice. */
+ if( *pUsed == true )
+ {
+ status = MQTTBadResponse;
+ }
+ /* Validate the length and decode. */
+ else if( *pPropertyLength < sizeof( uint8_t ) )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ if( pProperty != NULL )
+ {
+ *pProperty = *pLocalIndex;
+ }
+
+ pLocalIndex = &pLocalIndex[ sizeof( uint8_t ) ];
+ *pUsed = true;
+ *pPropertyLength -= sizeof( uint8_t );
+ }
+
+ *pIndex = pLocalIndex;
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUtf8( const char ** pProperty,
+ size_t * pLength,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ uint8_t * pLocalIndex = *pIndex;
+ MQTTStatus_t status = MQTTSuccess;
+ uint16_t length;
+
+ assert( pIndex != NULL );
+ assert( pPropertyLength != NULL );
+ assert( pUsed != NULL );
+
+ /* Protocol error to include the same property twice. */
+ if( *pUsed == true )
+ {
+ status = MQTTBadResponse;
+ }
+ /* Validate the length and decode. */
+ else if( *pPropertyLength < sizeof( uint16_t ) )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ length = UINT16_DECODE( pLocalIndex );
+ pLocalIndex = &pLocalIndex[ sizeof( uint16_t ) ];
+ *pPropertyLength -= sizeof( uint16_t );
+
+ if( *pPropertyLength < length )
+ {
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ if( ( pProperty != NULL ) && ( pLength != NULL ) )
+ {
+ *pProperty = ( const char * ) pLocalIndex;
+ *pLength = length;
+ }
+
+ pLocalIndex = &pLocalIndex[ length ];
+ *pPropertyLength -= length;
+ *pUsed = true;
+ }
+ }
+
+ *pIndex = pLocalIndex;
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeVariableLength( const uint8_t * pBuffer,
+ size_t bufferLength,
+ uint32_t * pLength )
+{
+ uint32_t remainingLength = 0;
+ uint32_t multiplier = 1;
+ size_t bytesDecoded = 0;
+ uint8_t encodedByte = 0;
+ size_t localBufferLength = bufferLength;
+ MQTTStatus_t status = MQTTSuccess;
+
+ assert( pLength != NULL );
+ assert( pBuffer != NULL );
+
+ /* This algorithm is copied from the MQTT 5.0 spec. */
+ do
+ {
+ if( multiplier > 2097152U ) /* 128 ^ 3 */
+ {
+ LogError( ( "Invalid remaining length in the packet.\n" ) );
+ remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ if( localBufferLength > 0U )
+ {
+ encodedByte = pBuffer[ bytesDecoded ];
+ remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
+ multiplier *= 128U;
+ bytesDecoded++;
+ localBufferLength--;
+ }
+ else
+ {
+ status = MQTTBadResponse;
+ }
+ }
+
+ /* If the response is incorrect then break out
+ * of the loop. */
+ if( ( remainingLength >= MQTT_REMAINING_LENGTH_INVALID ) ||
+ ( status != MQTTSuccess ) )
+ {
+ status = MQTTBadResponse;
+ break;
+ }
+ } while( ( encodedByte & 0x80U ) != 0U );
+
+ if( status == MQTTSuccess )
+ {
+ /* Check that the decoded remaining length conforms to the MQTT specification. */
+ size_t expectedSize = variableLengthEncodedSize( remainingLength );
+
+ if( bytesDecoded != expectedSize )
+ {
+ LogError( ( "Expected and actual length of decoded bytes do not match.\n" ) );
+ status = MQTTBadResponse;
+ }
+ else
+ {
+ *pLength = remainingLength;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * encodeVariableLength( uint8_t * pDestination,
+ uint32_t length )
+{
+ uint8_t lengthByte;
+ uint8_t * pLengthEnd = NULL;
+ uint32_t remainingLength = length;
+
+ assert( pDestination != NULL );
+
+ pLengthEnd = pDestination;
+
+ /* This algorithm is copied from the MQTT 5.0 spec. */
+ do
+ {
+ lengthByte = ( uint8_t ) ( remainingLength % 128U );
+ remainingLength = remainingLength / 128U;
+
+ /* Set the high bit of this byte, indicating that there's more data. */
+ if( remainingLength > 0U )
+ {
+ UINT8_SET_BIT( lengthByte, 7 );
+ }
+
+ /* Output a single encoded byte. */
+ *pLengthEnd = lengthByte;
+ pLengthEnd++;
+ } while( remainingLength > 0U );
+
+ return pLengthEnd;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * serializeAckFixed( uint8_t * pIndex,
+ uint8_t packetType,
+ uint16_t packetId,
+ uint32_t remainingLength,
+ MQTTSuccessFailReasonCode_t reasonCode )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ /* The first byte in the publish ack packet is the control packet type. */
+ *pIndexLocal = packetType;
+ pIndexLocal++;
+ /* After the packet type fixed header has remaining length. */
+ pIndexLocal = encodeVariableLength( pIndexLocal, remainingLength );
+ /* Encode the packet id. */
+ pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( packetId );
+ pIndexLocal[ 1 ] = UINT16_LOW_BYTE( packetId );
+ pIndexLocal = &pIndexLocal[ 2 ];
+ /* We are now sending the ack. */
+ *pIndexLocal = ( uint8_t ) reasonCode;
+ pIndexLocal++;
+ return pIndexLocal;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * serializeConnectFixedHeader( uint8_t * pIndex,
+ const MQTTConnectInfo_t * pConnectInfo,
+ const MQTTPublishInfo_t * pWillInfo,
+ uint32_t remainingLength )
+{
+ uint8_t * pIndexLocal = pIndex;
+ uint8_t connectFlags = 0U;
+
+ /* The first byte in the CONNECT packet is the control packet type. */
+ *pIndexLocal = MQTT_PACKET_TYPE_CONNECT;
+ pIndexLocal++;
+
+ /* The remaining length of the CONNECT packet is encoded starting from the
+ * second byte. The remaining length does not include the length of the fixed
+ * header or the encoding of the remaining length. */
+ pIndexLocal = encodeVariableLength( pIndexLocal, remainingLength );
+
+ /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable
+ * header. This string is 4 bytes long. */
+ pIndexLocal = encodeString( pIndexLocal, "MQTT", 4 );
+
+ /* The MQTT protocol version is the second field of the variable header. */
+
+ *pIndexLocal = MQTT_VERSION_5;
+
+ pIndexLocal++;
+
+ /* Set the clean session flag if needed. */
+ if( pConnectInfo->cleanSession == true )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
+ }
+
+ /* Set the flags for username and password if provided. */
+ if( pConnectInfo->pUserName != NULL )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
+ }
+
+ if( pConnectInfo->pPassword != NULL )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
+ }
+
+ /* Set will flag if a Last Will and Testament is provided. */
+ if( pWillInfo != NULL )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
+
+ /* Flags only need to be changed for Will QoS 1 or 2. */
+ if( pWillInfo->qos == MQTTQoS1 )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
+ }
+ else if( pWillInfo->qos == MQTTQoS2 )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
+ }
+ else
+ {
+ /* Empty else MISRA 15.7 */
+ }
+
+ if( pWillInfo->retain == true )
+ {
+ UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
+ }
+ }
+
+ *pIndexLocal = connectFlags;
+ pIndexLocal++;
+
+ /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */
+ pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );
+ pIndexLocal[ 1 ] = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );
+ pIndexLocal = &pIndexLocal[ 2 ];
+
+ return pIndexLocal;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * serializeSubscribeHeader( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId )
+{
+ uint8_t * pIterator = pIndex;
+
+ /* The first byte in SUBSCRIBE is the packet type. */
+ *pIterator = MQTT_PACKET_TYPE_SUBSCRIBE;
+ pIterator++;
+
+ /* Encode the "Remaining length" starting from the second byte. */
+ pIterator = encodeVariableLength( pIterator, remainingLength );
+
+ /* Place the packet identifier into the SUBSCRIBE packet. */
+ pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
+ pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
+ /* Advance the pointer. */
+ pIterator = &pIterator[ 2 ];
+
+ return pIterator;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * serializeUnsubscribeHeader( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId )
+{
+ uint8_t * pIterator = pIndex;
+
+ /* The first byte in UNSUBSCRIBE is the packet type. */
+ *pIterator = MQTT_PACKET_TYPE_UNSUBSCRIBE;
+ pIterator++;
+
+ /* Encode the "Remaining length" starting from the second byte. */
+ pIterator = encodeVariableLength( pIterator, remainingLength );
+
+ /* Place the packet identifier into the SUBSCRIBE packet. */
+ pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
+ pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
+ /* Increment the pointer. */
+ pIterator = &pIterator[ 2 ];
+
+ return pIterator;
+}
+
+/*-----------------------------------------------------------*/
+
+uint8_t * serializeDisconnectFixed( uint8_t * pIndex,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ assert( pIndex != NULL );
+ /* The first byte in the publish ack packet is the control packet type. */
+ *pIndexLocal = MQTT_PACKET_TYPE_DISCONNECT;
+ pIndexLocal++;
+
+ /* After the packet type fixed header has remaining length. */
+ pIndexLocal = encodeVariableLength( pIndexLocal, remainingLength );
+
+ if( pReasonCode != NULL )
+ {
+ /* Encode the reason code. */
+ *pIndexLocal = ( uint8_t ) *pReasonCode;
+ pIndexLocal++;
+ }
+
+ return pIndexLocal;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeSubackPropertyLength( const uint8_t * pIndex,
+ uint32_t remainingLength,
+ uint32_t * subackPropertyLength )
+{
+ MQTTStatus_t status;
+ const uint8_t * pLocalIndex = pIndex;
+ uint32_t propertyLength = 0U;
+
+ status = decodeVariableLength( pLocalIndex, remainingLength - sizeof( uint16_t ), &propertyLength );
+
+ if( status == MQTTSuccess )
+ {
+ *subackPropertyLength = ( propertyLength + variableLengthEncodedSize( propertyLength ) );
+
+ if( *subackPropertyLength > ( remainingLength - sizeof( uint16_t ) ) )
+ {
+ status = MQTTBadResponse;
+ }
+ }
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
diff --git a/source/core_mqtt_state.c b/source/core_mqtt_state.c
index 151c24b8b..215b5fb79 100644
--- a/source/core_mqtt_state.c
+++ b/source/core_mqtt_state.c
@@ -535,7 +535,7 @@ static MQTTStatus_t addRecord( MQTTPubAckInfo_t * records,
/* Start from end so first available index will be populated.
* Available index is always found after the last element in the records.
* This is to make sure the relative order of the records in order to meet
- * the message ordering requirement of MQTT spec 3.1.1. */
+ * the message ordering requirement of MQTT spec 5.0. */
for( index = ( ( int32_t ) recordCount - 1 ); index >= 0; index-- )
{
/* Available index is only found after packet at the highest index. */
@@ -1097,7 +1097,7 @@ uint16_t MQTT_PubrelToResend( const MQTTContext_t * pMqttContext,
else
{
/* PUBREL for packets in state #MQTTPubCompPending and #MQTTPubRelSend
- * would need to be resent when a session is reestablished.*/
+ * would need to be resent when a session is reestablished. */
UINT16_SET_BIT( searchStates, MQTTPubCompPending );
UINT16_SET_BIT( searchStates, MQTTPubRelSend );
packetId = stateSelect( pMqttContext, searchStates, pCursor );
diff --git a/source/include/core_mqtt.h b/source/include/core_mqtt.h
index c4f2357dd..f7ab6f507 100644
--- a/source/include/core_mqtt.h
+++ b/source/include/core_mqtt.h
@@ -24,7 +24,7 @@
/**
* @file core_mqtt.h
- * @brief User-facing functions of the MQTT 3.1.1 library.
+ * @brief User-facing functions of the MQTT 5.0 library.
*/
#ifndef CORE_MQTT_H
#define CORE_MQTT_H
@@ -55,7 +55,7 @@
* @ingroup mqtt_constants
* @brief Invalid packet identifier.
*
- * Zero is an invalid packet identifier as per MQTT v3.1.1 spec.
+ * Zero is an invalid packet identifier as per MQTT 5.0 spec.
*/
#define MQTT_PACKET_ID_INVALID ( ( uint16_t ) 0U )
@@ -88,24 +88,86 @@ typedef struct MQTTVec MQTTVec_t;
*
* @return The time elapsed in milliseconds.
*/
-typedef uint32_t (* MQTTGetCurrentTimeFunc_t )( void );
+typedef uint32_t ( * MQTTGetCurrentTimeFunc_t )( void );
/**
* @ingroup mqtt_callback_types
* @brief Application callback for receiving incoming publishes and incoming
- * acks.
+ * acks, as well as adding properties to outgoing publish acks.
*
* @note This callback will be called only if packets are deserialized with a
* result of #MQTTSuccess or #MQTTServerRefused. The latter can be obtained
- * when deserializing a SUBACK, indicating a broker's rejection of a subscribe.
+ * when deserializing a SUBACK indicating a broker's rejection of a subscribe,
+ * or a CONNACK indicating a broker's rejection of a connection.
*
* @param[in] pContext Initialized MQTT context.
* @param[in] pPacketInfo Information on the type of incoming MQTT packet.
* @param[in] pDeserializedInfo Deserialized information from incoming packet.
+ * @param[out] pReasonCode Reason code for the incoming packet.
+ * @param[out] pSendPropsBuffer Properties to be sent in the outgoing packet.
+ * @param[in] pGetPropsBuffer Properties to be received in the incoming packet.
+ *
+ * @note Get optional properties of incoming packets by calling these functions:
+ *
+ *
+ * - Connack Properties:
+ * - #MQTTPropGet_SessionExpiry
+ * - #MQTTPropGet_ReceiveMax
+ * - #MQTTPropGet_MaxQos
+ * - #MQTTPropGet_RetainAvailable
+ * - #MQTTPropGet_MaxPacketSize
+ * - #MQTTPropGet_AssignedClientId
+ * - #MQTTPropGet_TopicAliasMax
+ * - #MQTTPropGet_ReasonString
+ * - #MQTTPropGet_UserProp
+ * - #MQTTPropGet_WildcardId
+ * - #MQTTPropGet_SubsIdAvailable
+ * - #MQTTPropGet_SharedSubAvailable
+ * - #MQTTPropGet_ServerKeepAlive
+ * - #MQTTPropGet_ResponseInfo
+ * - #MQTTPropGet_ServerRef
+ * - #MQTTPropGet_AuthMethod
+ * - #MQTTPropGet_AuthData
+ *
+ * - Publish Properties:
+ * - #MQTTPropGet_TopicAlias
+ * - #MQTTPropGet_PayloadFormatIndicator
+ * - #MQTTPropGet_ResponseTopic
+ * - #MQTTPropGet_CorrelationData
+ * - #MQTTPropGet_MessageExpiryInterval
+ * - #MQTTPropGet_ContentType
+ * - #MQTTPropGet_SubscriptionId
+ * - #MQTTPropGet_UserProp
+ *
+ * - Ack Properties (PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK):
+ * - #MQTTPropGet_ReasonString
+ * - #MQTTPropGet_UserProp
+ *
+ * - Disconnect Properties:
+ * - #MQTTPropGet_SessionExpiry
+ * - #MQTTPropGet_ReasonString
+ * - #MQTTPropGet_UserProp
+ * - #MQTTPropGet_ServerRef
+ *
+ * @note Add optional properties to outgoing publish ack packets by calling these functions:
+ *
+ * - #MQTTPropAdd_UserProp
+ * - #MQTTPropAdd_ReasonString
+ * @return
+ * - true Event callback was able to process the packet
+ * - false This is not an error but just a flag that tells
+ * the user that the eventcallback was unable to process
+ * a packet due to application specific reasons.
+ * The application should recall the processloop after
+ * making sure that it would be able to process the
+ * received packet again.
*/
-typedef void (* MQTTEventCallback_t )( struct MQTTContext * pContext,
- struct MQTTPacketInfo * pPacketInfo,
- struct MQTTDeserializedInfo * pDeserializedInfo );
+typedef bool ( * MQTTEventCallback_t )( struct MQTTContext * pContext,
+ struct MQTTPacketInfo * pPacketInfo,
+ struct MQTTDeserializedInfo * pDeserializedInfo,
+ enum MQTTSuccessFailReasonCode * pReasonCode,
+ struct MQTTPropBuilder * pSendPropsBuffer,
+ struct MQTTPropBuilder * pGetPropsBuffer );
/**
* @brief User defined callback used to store outgoing publishes. Used to track any publish
@@ -120,9 +182,9 @@ typedef void (* MQTTEventCallback_t )( struct MQTTContext * pContext,
* @return True if the copy is successful else false.
*/
/* @[define_mqtt_retransmitstorepacket] */
-typedef bool ( * MQTTStorePacketForRetransmit)( struct MQTTContext * pContext,
- uint16_t packetId,
- MQTTVec_t * pMqttVec );
+typedef bool ( * MQTTStorePacketForRetransmit )( struct MQTTContext * pContext,
+ uint16_t packetId,
+ MQTTVec_t * pMqttVec );
/* @[define_mqtt_retransmitstorepacket] */
/**
@@ -140,10 +202,10 @@ typedef bool ( * MQTTStorePacketForRetransmit)( struct MQTTContext * pContext,
* @return True if the retreive is successful else false.
*/
/* @[define_mqtt_retransmitretrievepacket] */
-typedef bool ( * MQTTRetrievePacketForRetransmit)( struct MQTTContext * pContext,
- uint16_t packetId,
- uint8_t ** pSerializedMqttVec,
- size_t * pSerializedMqttVecLen );
+typedef bool ( * MQTTRetrievePacketForRetransmit )( struct MQTTContext * pContext,
+ uint16_t packetId,
+ uint8_t ** pSerializedMqttVec,
+ size_t * pSerializedMqttVecLen );
/* @[define_mqtt_retransmitretrievepacket] */
/**
@@ -154,8 +216,8 @@ typedef bool ( * MQTTRetrievePacketForRetransmit)( struct MQTTContext * pContext
* @param[in] packetId Copied publish packet identifier.
*/
/* @[define_mqtt_retransmitclearpacket] */
-typedef void (* MQTTClearPacketForRetransmit)( struct MQTTContext * pContext,
- uint16_t packetId );
+typedef void ( * MQTTClearPacketForRetransmit )( struct MQTTContext * pContext,
+ uint16_t packetId );
/* @[define_mqtt_retransmitclearpacket] */
/**
@@ -255,10 +317,15 @@ typedef struct MQTTContext
TransportInterface_t transportInterface;
/**
- * @brief The buffer used in sending and receiving packets from the network.
+ * @brief The buffer used in receiving packets from the network.
*/
MQTTFixedBuffer_t networkBuffer;
+ /**
+ * @brief The buffer used to store properties for outgoing ack packets.
+ */
+ MQTTPropBuilder_t ackPropsBuffer;
+
/**
* @brief The next available ID for outgoing MQTT packets.
*/
@@ -305,6 +372,11 @@ typedef struct MQTTContext
uint32_t pingReqSendTimeMs; /**< @brief Timestamp of the last sent PINGREQ. */
bool waitingForPingResp; /**< @brief If the library is currently awaiting a PINGRESP. */
+ /**
+ * @brief Persistent Connection Properties, populated in the CONNECT and the CONNACK.
+ */
+ MQTTConnectionProperties_t connectionProperties;
+
/**
* @brief User defined API used to store outgoing publishes.
*/
@@ -331,6 +403,7 @@ typedef struct MQTTDeserializedInfo
uint16_t packetIdentifier; /**< @brief Packet ID of deserialized packet. */
MQTTPublishInfo_t * pPublishInfo; /**< @brief Pointer to deserialized publish info. */
MQTTStatus_t deserializationResult; /**< @brief Return code of deserialization. */
+ MQTTReasonCodeInfo_t * pReasonCode; /**< @brief Pointer to deserialized ack info. */
} MQTTDeserializedInfo_t;
/**
@@ -358,8 +431,8 @@ typedef struct MQTTDeserializedInfo
* for the entire lifetime of the @p pContext and must not be used by another context and/or
* application.
*
- * @return #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSuccess otherwise.
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
*
* Example
* @code{c}
@@ -428,9 +501,10 @@ MQTTStatus_t MQTT_Init( MQTTContext_t * pContext,
* publishes.
* @param[in] incomingPublishCount Maximum number of records which can be kept in the memory
* pointed to by @p pIncomingPublishRecords.
- *
- * @return #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSuccess otherwise.
+ * @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.
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
*
* Example
* @code{c}
@@ -473,7 +547,16 @@ MQTTStatus_t MQTT_Init( MQTTContext_t * pContext,
* {
* // We do not expect any incoming publishes in this example, therefore the incoming
* // publish pointer is NULL and the count is zero.
- * status = MQTT_InitStatefulQoS( &mqttContext, outgoingPublishes, outgoingPublishCount, NULL, 0 );
+ * // The buffer is used to store properties of outgoing publish-ACKS.
+ * uint8_t ackPropsBuf[ 500 ];
+ * size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ * status = MQTT_InitStatefulQoS( &mqttContext,
+ * outgoingPublishes,
+ * outgoingPublishCount,
+ * NULL,
+ * 0,
+ * ackPropsBuf,
+ * ackPropsBufLength );
*
* // Now QoS1 and/or QoS2 publishes can be sent with this context.
* }
@@ -484,7 +567,9 @@ MQTTStatus_t MQTT_InitStatefulQoS( MQTTContext_t * pContext,
MQTTPubAckInfo_t * pOutgoingPublishRecords,
size_t outgoingPublishCount,
MQTTPubAckInfo_t * pIncomingPublishRecords,
- size_t incomingPublishCount );
+ size_t incomingPublishCount,
+ uint8_t * pAckPropsBuf,
+ size_t ackPropsBufLength );
/* @[declare_mqtt_initstatefulqos] */
/**
@@ -624,23 +709,34 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext );
* @param[in] timeoutMs Maximum time in milliseconds to wait for a CONNACK packet.
* A zero timeout makes use of the retries for receiving CONNACK as configured with
* #MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT.
+ * @param[in] pPropertyBuilder Properties to be sent in the outgoing packet.
+ * @param[in] pWillPropertyBuilder Will Properties to be sent in the outgoing packet.
* @param[out] pSessionPresent This value will be set to true if a previous session
* was present; otherwise it will be set to false. It is only relevant if not
* establishing a clean session.
*
- * @return #MQTTNoMemory if the #MQTTContext_t.networkBuffer is too small to
- * hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSendFailed if transport send failed;
- * #MQTTRecvFailed if transport receive failed for CONNACK;
+ * @return
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSendFailed if transport send failed;
+ * #MQTTRecvFailed if transport receive failed for CONNACK;
* #MQTTNoDataAvailable if no data available to receive in transport until
- * the @p timeoutMs for CONNACK;
- * #MQTTStatusConnected if the connection is already established
+ * the @p timeoutMs for CONNACK;
+ * #MQTTStatusConnected if the connection is already established
* #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
- * before calling any other API
- * MQTTPublishRetrieveFailed if on an unclean session connection, the copied
- * publishes are not retrieved successfully for retransmission
- * #MQTTSuccess otherwise.
+ * before calling any other API
+ * #MQTTPublishRetrieveFailed if on an unclean session connection, the copied
+ * publishes are not retrieved successfully for retransmission
+ * #MQTTBadResponse if the received CONNACK packet is malformed
+ * #MQTTServerRefused if the server refuses the connection in the CONNACK.
+ * #MQTTEventCallbackFailed if the user defined callback fails.
+ * #MQTTSuccess otherwise.
+ *
+ * @note If no properties are provided (by setting @p pPropertyBuilder to NULL), coreMQTT
+ * will add a property to the connect packet to limit the maximum packet size that the
+ * broker can send to be equal to the application provided buffer to the #MQTT_Init API.
+ * This prevents the case when the packet is bigger than the buffer at which point,
+ * coreMQTT cannot handle the packet, neither can it drop it as MQTT protocol doesn't
+ * allow it.
*
* @note This API may spend more time than provided in the timeoutMS parameters in
* certain conditions as listed below:
@@ -660,6 +756,28 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext );
* 2 bytes. In the worst case, it can happen that the remaining 2 bytes are never
* received and this API will end up spending timeoutMs + transport receive timeout.
*
+ * Functions to add optional properties to the CONNECT packet are:
+ *
+ * Connect Properties:
+ * - #MQTTPropAdd_SessionExpiry
+ * - #MQTTPropAdd_ReceiveMax
+ * - #MQTTPropAdd_MaxPacketSize
+ * - #MQTTPropAdd_TopicAliasMax
+ * - #MQTTPropAdd_RequestRespInfo
+ * - #MQTTPropAdd_RequestProbInfo
+ * - #MQTTPropAdd_UserProp
+ * - #MQTTPropAdd_AuthMethod
+ * - #MQTTPropAdd_AuthData
+ *
+ * Will Properties:
+ * - #MQTTPropAdd_WillDelayInterval
+ * - #MQTTPropAdd_PayloadFormat
+ * - #MQTTPropAdd_MessageExpiry
+ * - #MQTTPropAdd_ResponseTopic
+ * - #MQTTPropAdd_CorrelationData
+ * - #MQTTPropAdd_ContentType
+ * - #MQTTPropAdd_UserProp
+ *
* Example
* @code{c}
*
@@ -685,6 +803,15 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext );
* connectInfo.userNameLength = strlen( connectInfo.pUserName );
* connectInfo.pPassword = "somePassword";
* connectInfo.passwordLength = strlen( connectInfo.pPassword );
+ * // Optional properties to be sent in the CONNECT packet.
+ * MQTTPropBuilder_t connectPropsBuilder;
+ * uint8_t connectPropsBuffer[ 100 ];
+ * size_t connectPropsBufferLength = sizeof( connectPropsBuffer );
+ * status = MQTTPropertyBuilder_Init( &connectPropsBuilder, connectPropsBuffer, connectPropsBufferLength );
+ *
+ * // Set a property in the connectPropsBuilder
+ * uint32_t maxPacketSize = 100 ;
+ * status = MQTTPropAdd_ConnMaxPacketSize(&connectPropsBuilder, maxPacketSize);
*
* // The last will and testament is optional, it will be published by the broker
* // should this client disconnect without sending a DISCONNECT packet.
@@ -693,9 +820,17 @@ MQTTStatus_t MQTT_CheckConnectStatus( const MQTTContext_t * pContext );
* willInfo.topicNameLength = strlen( willInfo.pTopicName );
* willInfo.pPayload = "LWT Message";
* willInfo.payloadLength = strlen( "LWT Message" );
+ * // Optional Will Properties to be sent in the CONNECT packet.
+ * MQTTPropBuilder_t willPropsBuilder;
+ * uint8_t willPropsBuffer[ 100 ];
+ * size_t willPropsBufferLength = sizeof( willPropsBuffer );
+ * status = MQTTPropertyBuilder_Init( &willPropsBuilder, willPropsBuffer, willPropsBufferLength );
+ *
+ * // Set a property in the willPropsBuilder
+ * status = MQTTPropAdd_PubPayloadFormat( &willPropsBuilder, 1);
*
* // Send the connect packet. Use 100 ms as the timeout to wait for the CONNACK packet.
- * status = MQTT_Connect( pContext, &connectInfo, &willInfo, 100, &sessionPresent );
+ * status = MQTT_Connect( pContext, &connectInfo, &willInfo, 100, &sessionPresent, &connectPropsBuilder, &willPropsBuilder );
*
* if( status == MQTTSuccess )
* {
@@ -711,7 +846,9 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
uint32_t timeoutMs,
- bool * pSessionPresent );
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTPropBuilder_t * pWillPropertyBuilder );
/* @[declare_mqtt_connect] */
/**
@@ -723,15 +860,20 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
* @param[in] subscriptionCount The number of elements in @ pSubscriptionList
* array.
* @param[in] packetId Packet ID generated by #MQTT_GetPacketId.
- *
- * @return #MQTTNoMemory if the #MQTTContext_t.networkBuffer is too small to
- * hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSendFailed if transport write failed;
- * #MQTTStatusNotConnected if the connection is not established yet
+ * @param[in] pPropertyBuilder Properties to be sent in the outgoing packet.
+ * @return
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTBadResponse if there is an error in property parsing;
+ * #MQTTSendFailed if transport write failed;
+ * #MQTTStatusNotConnected if the connection is not established yet
* #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
- * before calling any other API
- * #MQTTSuccess otherwise.
+ * before calling any other API
+ * #MQTTSuccess otherwise.
+ *
+ * Functions to add optional properties to the SUBSCRIBE packet are:
+ *
+ * - #MQTTPropAdd_SubscriptionId
+ * - #MQTTPropAdd_UserProp
*
* Example
* @code{c}
@@ -753,11 +895,18 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
* subscriptionList[ i ].pTopicFilter = filters[ i ];
* subscriptionList[ i ].topicFilterLength = strlen( filters[ i ] );
* }
+ * // Optional Properties to be sent in the SUBSCRIBE packet
+ * MQTTPropBuilder_t propertyBuilder;
+ * uint8_t propertyBuffer[ 100 ];
+ * size_t propertyBufferLength = sizeof( propertyBuffer );
+ * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
+ *
+ * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, 1);
*
* // Obtain a new packet id for the subscription.
* packetId = MQTT_GetPacketId( pContext );
*
- * status = MQTT_Subscribe( pContext, &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId );
+ * status = MQTT_Subscribe( pContext, &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId, propertyBuilder );
*
* if( status == MQTTSuccess )
* {
@@ -768,10 +917,13 @@ MQTTStatus_t MQTT_Connect( MQTTContext_t * pContext,
* @endcode
*/
/* @[declare_mqtt_subscribe] */
+
MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId );
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder );
+
/* @[declare_mqtt_subscribe] */
/**
@@ -780,16 +932,28 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
* @param[in] pContext Initialized MQTT context.
* @param[in] pPublishInfo MQTT PUBLISH packet parameters.
* @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] pPropertyBuilder Properties to be sent in the outgoing packet.
*
- * @return #MQTTNoMemory if pBuffer is too small to hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSendFailed if transport write failed;
- * #MQTTStatusNotConnected if the connection is not established yet
+ * @return
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTBadResponse if there is an error in property parsing;
+ * #MQTTSendFailed if transport write failed;
+ * #MQTTStatusNotConnected if the connection is not established yet
* #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
- * before calling any other API
+ * before calling any other API
* #MQTTPublishStoreFailed if the user provided callback to copy and store the
- * outgoing publish packet fails
- * #MQTTSuccess otherwise.
+ * outgoing publish packet fails
+ * #MQTTSuccess otherwise.
+ *
+ * Functions to add optional properties to the PUBLISH packet are:
+ *
+ * - #MQTTPropAdd_PayloadFormat
+ * - #MQTTPropAdd_MessageExpiry
+ * - #MQTTPropAdd_TopicAlias
+ * - #MQTTPropAdd_ResponseTopic
+ * - #MQTTPropAdd_CorrelationData
+ * - #MQTTPropAdd_ContentType
+ * - #MQTTPropAdd_UserProp
*
* Example
* @code{c}
@@ -807,11 +971,19 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
* publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
* publishInfo.pPayload = "Hello World!";
* publishInfo.payloadLength = strlen( "Hello World!" );
+ * // Optional properties to be sent in the PUBLISH packet.
+ * MQTTPropBuilder_t propertyBuilder;
+ * uint8_t propertyBuffer[ 100 ];
+ * size_t propertyBufferLength = sizeof( propertyBuffer );
+ * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
+ *
+ * // Set a property in the propertyBuilder
+ * status = MQTTPropAdd_PubPayloadFormat( &propertyBuilder, 1);
*
* // Packet ID is needed for QoS > 0.
* packetId = MQTT_GetPacketId( pContext );
*
- * status = MQTT_Publish( pContext, &publishInfo, packetId );
+ * status = MQTT_Publish( pContext, &publishInfo, packetId, &propertyBuilder );
*
* if( status == MQTTSuccess )
* {
@@ -823,7 +995,8 @@ MQTTStatus_t MQTT_Subscribe( MQTTContext_t * pContext,
/* @[declare_mqtt_publish] */
MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
const MQTTPublishInfo_t * pPublishInfo,
- uint16_t packetId );
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder );
/* @[declare_mqtt_publish] */
/**
@@ -873,15 +1046,20 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext );
* @param[in] pSubscriptionList List of MQTT subscription info.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
* @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] pPropertyBuilder Properties to be sent in the outgoing packet.
*
- * @return #MQTTNoMemory if the #MQTTContext_t.networkBuffer is too small to
- * hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSendFailed if transport write failed;
- * #MQTTStatusNotConnected if the connection is not established yet
- * #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
- * before calling any other API
- * #MQTTSuccess otherwise.
+ * @return
+ * - #MQTTBadParameter if invalid parameters are passed;
+ * - #MQTTBadResponse if invalid properties are parsed;
+ * - #MQTTSendFailed if transport write failed;
+ * - #MQTTStatusNotConnected if the connection is not established yet
+ * - #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
+ * before calling any other API
+ * - #MQTTSuccess otherwise.
+ *
+ * Functions to add optional properties to the UNSUBSCRIBE packet are:
+ *
+ * - #MQTTPropAdd_UserProp
*
* Example
* @code{c}
@@ -906,8 +1084,22 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext );
*
* // Obtain a new packet id for the unsubscribe request.
* packetId = MQTT_GetPacketId( pContext );
+ * // Optional properties to be sent in the UNSUBSCRIBE packet.
+ * MQTTPropBuilder_t propertyBuilder;
+ * uint8_t propertyBuffer[ 100 ];
+ * size_t propertyBufferLength = sizeof( propertyBuffer );
+ * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
*
- * status = MQTT_Unsubscribe( pContext, &unsubscribeList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId );
+ * // Set a property in the propertyBuilder
+ * MQTTUserProperty_t userProperty;
+ * userProperty.pKey = "key";
+ * userProperty.keyLength = strlen( userProperty.pKey );
+ * userProperty.pValue = "value";
+ * *userProperty.valueLength = strlen( userProperty.pValue );
+ *
+ * status = MQTTPropAdd_UserProp( &propertyBuilder,&userProperty);
+ *
+ * status = MQTT_Unsubscribe( pContext, &unsubscribeList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, packetId, &propertyBuilder );
*
* if( status == MQTTSuccess )
* {
@@ -920,23 +1112,62 @@ MQTTStatus_t MQTT_Ping( MQTTContext_t * pContext );
MQTTStatus_t MQTT_Unsubscribe( MQTTContext_t * pContext,
const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- uint16_t packetId );
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pPropertyBuilder );
/* @[declare_mqtt_unsubscribe] */
/**
- * @brief Disconnect an MQTT session.
+ * @brief Sends MQTT DISCONNECT for a given reason code
*
* @param[in] pContext Initialized and connected MQTT context.
+ * @param[in] pPropertyBuilder Properties to be sent in the outgoing packet.
+ * @param[in] pReasonCode Optional reason code to be sent in the DISCONNECT packet.
+ * If NULL, then no reason code is sent.
+ *
+ * @return
+ * #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTBadResponse if invalid properties are parsed;
+ * #MQTTSendFailed if transport send failed;
+ * #MQTTStatusNotConnected if the connection is not established yet and a PING
+ * or an ACK is being sent.
+ * #MQTTStatusDisconnectPending if the user is expected to call MQTT_Disconnect
+ * before calling any other API
+ * #MQTTSuccess otherwise.
*
- * @return #MQTTNoMemory if the #MQTTContext_t.networkBuffer is too small to
- * hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSendFailed if transport send failed;
- * #MQTTStatusNotConnected if the connection is already disconnected
- * #MQTTSuccess otherwise.
+ * Functions to add optional properties to the DISCONNECT packet are:
+ *
+ * - #MQTTPropAdd_SessionExpiry
+ * - #MQTTPropAdd_ReasonString
+ * - #MQTTPropAdd_UserProp
+ *
+ * Example
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * // This context is assumed to be initialized and connected.
+ * MQTTContext_t * pContext;
+ * // Optional properties to be sent in the DISCONNECT packet.
+ * MQTTPropBuilder_t propertyBuilder;
+ * uint8_t propertyBuffer[ 100 ];
+ * size_t propertyBufferLength = sizeof( propertyBuffer );
+ * status = MQTTPropertyBuilder_Init( &propertyBuilder, propertyBuffer, propertyBufferLength );
+ *
+ * // Set a property in the propertyBuilder
+ * status = MQTTPropAdd_ReasonString( &propertyBuilder, "Disconnecting", 12);
+ *
+ * status = MQTT_Disconnect( pContext, &propertyBuilder, MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION );
+ *
+ * if( status == MQTTSuccess )
+ * {
+ * // The DISCONNECT packet was sent successfully. The connection is now closed.
+ * }
+ * @endcode
*/
/* @[declare_mqtt_disconnect] */
-MQTTStatus_t MQTT_Disconnect( MQTTContext_t * pContext );
+MQTTStatus_t MQTT_Disconnect( MQTTContext_t * pContext,
+ const MQTTPropBuilder_t * pPropertyBuilder,
+ MQTTSuccessFailReasonCode_t * pReasonCode );
/* @[declare_mqtt_disconnect] */
/**
@@ -1066,7 +1297,7 @@ MQTTStatus_t MQTT_ReceiveLoop( MQTTContext_t * pContext );
/* @[declare_mqtt_receiveloop] */
/**
- * @brief Get a packet ID that is valid according to the MQTT 3.1.1 spec.
+ * @brief Get a packet ID that is valid according to the MQTT 5.0 spec.
*
* @param[in] pContext Initialized MQTT context.
*
@@ -1078,7 +1309,7 @@ uint16_t MQTT_GetPacketId( MQTTContext_t * pContext );
/**
* @brief A utility function that determines whether the passed topic filter and
- * topic name match according to the MQTT 3.1.1 protocol specification.
+ * topic name match according to the MQTT 5.0 protocol specification.
*
* @param[in] pTopicName The topic name to check.
* @param[in] topicNameLength Length of the topic name.
@@ -1090,7 +1321,7 @@ uint16_t MQTT_GetPacketId( MQTTContext_t * pContext );
* value is set to true; otherwise if there is no match then it is set to false.
*
* @note The API assumes that the passed topic name is valid to meet the
- * requirements of the MQTT 3.1.1 specification. Invalid topic names (for example,
+ * requirements of the MQTT 5.0 specification. Invalid topic names (for example,
* containing wildcard characters) should not be passed to the function.
* Also, the API checks validity of topic filter for wildcard characters ONLY if
* the passed topic name and topic filter do not have an exact string match.
@@ -1121,9 +1352,9 @@ uint16_t MQTT_GetPacketId( MQTTContext_t * pContext );
* @endcode
*/
MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
- const uint16_t topicNameLength,
+ const size_t topicNameLength,
const char * pTopicFilter,
- const uint16_t topicFilterLength,
+ const size_t topicFilterLength,
bool * pIsMatch );
/**
@@ -1137,7 +1368,17 @@ MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
* - 0x00 - Success - Maximum QoS 0
* - 0x01 - Success - Maximum QoS 1
* - 0x02 - Success - Maximum QoS 2
- * - 0x80 - Failure
+ * These are the reason codes when the server refuses the request-
+ * - 0x80 - Topic Filter Refused
+ * - 0x83 - Implementation specific error.
+ * - 0x87 - Not authorized.
+ * - 0x8F - Invalid Topic Filter.
+ * - 0x91 - Packet identifier in use.
+ * - 0x97 - Quota exceeded.
+ * - 0x9E - Shared subscriptions not supported.
+ * - 0xA1 - Subscription identifiers not supported.
+ * - 0xA2 - Wildcard subscriptions not supported.
+ *
* Refer to #MQTTSubAckStatus_t for the status codes.
*
* @param[in] pSubackPacket The SUBACK packet whose payload is to be parsed.
@@ -1148,8 +1389,8 @@ MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
* SUBACK status is present in the packet.
*
* @return Returns one of the following:
- * - #MQTTBadParameter if the input SUBACK packet is invalid.
- * - #MQTTSuccess if parsing the payload was successful.
+ * - #MQTTBadParameter if the input SUBACK packet is invalid.
+ * - #MQTTSuccess if parsing the payload was successful.
*
* Example
* @code{c}
@@ -1160,10 +1401,13 @@ MQTTStatus_t MQTT_MatchTopic( const char * pTopicName,
*
* // MQTT_GetSubAckStatusCodes is intended to be used from the application
* // callback that is called by the library in MQTT_ProcessLoop or MQTT_ReceiveLoop.
- * void eventCallback(
+ * bool eventCallback(
* MQTTContext_t * pContext,
* MQTTPacketInfo_t * pPacketInfo,
* MQTTDeserializedInfo_t * pDeserializedInfo
+ * MQTTSuccessFailReasonCode_t * pReasonCode,
+ * MQTTPropBuilder_t * pSendPropsBuffer,
+ * MQTTPropBuilder_t * pGetPropsBuffer
* )
* {
* MQTTStatus_t status = MQTTSuccess;
@@ -1226,27 +1470,61 @@ const char * MQTT_Status_strerror( MQTTStatus_t status );
/* @[declare_mqtt_status_strerror] */
/**
- * @brief Get the bytes in a #MQTTVec pointer which can store the whole array as a an MQTT packet when calling MQTT_SerializeMQTTVec( void * pAllocatedMem, MQTTVec_t *pVec ) function.
+ * @brief Get the bytes in a #MQTTVec pointer which can store the whole array as a an
+ * MQTT packet when calling MQTT_SerializeMQTTVec( void * pAllocatedMem, MQTTVec_t *pVec ) function.
*
- * @param[in] pVec The #MQTTVec pointer given as input to the user defined #MQTTStorePacketForRetransmit callback function. Must not be NULL.
+ * @param[in] pVec The #MQTTVec pointer given as input to the user defined
+ * #MQTTStorePacketForRetransmit callback function. Must not be NULL.
+ * @param[out] pOutput The number of bytes in the vector. This value is invalid if the status is not
+ * #MQTTSuccess.
*
- * @return The bytes in the provided #MQTTVec array which can then be used to set aside memory to be used with MQTT_SerializeMQTTVec( void * pAllocatedMem, MQTTVec_t *pVec ) function.
+ * @return #MQTTSuccess when the calculation is successful. The provided #MQTTVec array can then be used to
+ * set aside memory to be used with MQTT_SerializeMQTTVec( void * pAllocatedMem, MQTTVec_t *pVec ) function.
+ * #MQTTBadParameter on failure.
*/
/* @[declare_mqtt_getbytesinmqttvec] */
-size_t MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec );
+MQTTStatus_t MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec,
+ size_t * pOutput );
/* @[declare_mqtt_getbytesinmqttvec] */
/**
* @brief Serialize the bytes in an array of #MQTTVec in the provided \p pAllocatedMem
*
- * @param[in] pAllocatedMem Memory in which to serialize the data in the #MQTTVec array. It must be of size provided by MQTT_GetBytesInMQTTVec( MQTTVec_t *pVec ). Should not be NULL.
- * @param[in] pVec The #MQTTVec pointer given as input to the user defined #MQTTStorePacketForRetransmit callback function. Must not be NULL.
+ * @param[in] pAllocatedMem Memory in which to serialize the data in the #MQTTVec array.
+ * It must be of size provided by MQTT_GetBytesInMQTTVec( const MQTTVec_t * pVec, size_t * pOutput ).
+ * Must not be NULL.
+ * @param[in] pVec The #MQTTVec pointer given as input to the user defined
+ * #MQTTStorePacketForRetransmit callback function. Must not be NULL.
*/
/* @[declare_mqtt_serializemqttvec] */
void MQTT_SerializeMQTTVec( uint8_t * pAllocatedMem,
const MQTTVec_t * pVec );
/* @[declare_mqtt_serializemqttvec] */
+/**
+ * @brief Get a human-readable string representation of an MQTT packet type.
+ *
+ * This function converts an MQTT packet type byte into a corresponding
+ * string representation for debugging and logging purposes.
+ *
+ * @param[in] packetType The MQTT packet type byte to convert.
+ *
+ * @return A pointer to a constant string containing the packet type name.
+ * Returns "UNKNOWN" if the packet type is not recognized.
+ *
+ * @note The returned string is statically allocated and should not be freed.
+ * @note For PUBLISH packets, the function masks the lower 4 bits (flags) and
+ * returns "PUBLISH" regardless of the QoS, DUP, or RETAIN flag values.
+ *
+ * Example
+ * @code{c}
+ * uint8_t packetType = MQTT_PACKET_TYPE_PUBLISH;
+ * const char * packetName = MQTT_GetPacketTypeString( packetType );
+ * printf( "Received packet: %s\n", packetName ); // Prints "Received packet: PUBLISH"
+ * @endcode
+ */
+const char * MQTT_GetPacketTypeString( uint8_t packetType );
+
/* *INDENT-OFF* */
#ifdef __cplusplus
}
diff --git a/source/include/core_mqtt_config_defaults.h b/source/include/core_mqtt_config_defaults.h
index 3fd79f974..1c3f95261 100644
--- a/source/include/core_mqtt_config_defaults.h
+++ b/source/include/core_mqtt_config_defaults.h
@@ -275,6 +275,26 @@
#define LogDebug( message )
#endif
+/**
+ * @brief Macro that is called in the MQTT library for logging "Trace" level
+ * messages.
+ *
+ * To enable trace level logging from MQTT library, this macro should be mapped to the
+ * application-specific logging implementation that supports trace logging.
+ *
+ * @note This logging macro is called in the MQTT library with parameters wrapped in
+ * double parentheses to be ISO C89/C90 standard compliant. For a reference
+ * POSIX implementation of the logging macros, refer to core_mqtt_config.h files, and the
+ * logging-stack in demos folder of the
+ * [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C/).
+ *
+ * Default value: Trace logging is turned off, and no code is generated for calls
+ * to the macro in the MQTT library on compilation.
+ */
+#ifndef LogTrace
+ #define LogTrace( message )
+#endif
+
/* *INDENT-OFF* */
#ifdef __cplusplus
}
diff --git a/source/include/core_mqtt_serializer.h b/source/include/core_mqtt_serializer.h
index 92c3ceeae..15365c416 100644
--- a/source/include/core_mqtt_serializer.h
+++ b/source/include/core_mqtt_serializer.h
@@ -24,7 +24,7 @@
/**
* @file core_mqtt_serializer.h
- * @brief User-facing functions for serializing and deserializing MQTT 3.1.1
+ * @brief User-facing functions for serializing and deserializing MQTT 5.0
* packets. This header should be included for building a lighter weight MQTT
* client than the managed CSDK MQTT library API in core_mqtt.h, by using the
* serializer and de-serializer functions exposed in this file's API.
@@ -64,6 +64,7 @@
#define MQTT_PACKET_TYPE_PINGREQ ( ( uint8_t ) 0xC0U ) /**< @brief PINGREQ (client-to-server). */
#define MQTT_PACKET_TYPE_PINGRESP ( ( uint8_t ) 0xD0U ) /**< @brief PINGRESP (server-to-client). */
#define MQTT_PACKET_TYPE_DISCONNECT ( ( uint8_t ) 0xE0U ) /**< @brief DISCONNECT (client-to-server). */
+#define MQTT_PACKET_TYPE_AUTH ( ( uint8_t ) 0xF0U ) /**< @brief AUTH (bidirectional). */
/** @} */
/**
@@ -72,6 +73,157 @@
*/
#define MQTT_PUBLISH_ACK_PACKET_SIZE ( 4UL )
+#define MQTT_SUBSCRIBE_QOS1 ( 0 ) /**< @brief MQTT SUBSCRIBE QoS1 flag. */
+#define MQTT_SUBSCRIBE_QOS2 ( 1 ) /**< @brief MQTT SUBSCRIBE QoS2 flag. */
+#define MQTT_SUBSCRIBE_NO_LOCAL ( 2 ) /**< @brief MQTT SUBSCRIBE no local flag. */
+#define MQTT_SUBSCRIBE_RETAIN_AS_PUBLISHED ( 3 ) /**< @brief MQTT SUBSCRIBE retain as published flag. */
+#define MQTT_SUBSCRIBE_RETAIN_HANDLING1 ( 4 ) /**<@brief MQTT SUBSCRIBE Retain Handling Option 1 */
+#define MQTT_SUBSCRIBE_RETAIN_HANDLING2 ( 5 ) /**<@brief Retain Handling Option 2 -> in core_mqtt_serializer.c */
+
+/* CONNECT PROPERTIES. */
+
+/**
+* @brief Session expiry id.
+*/
+#define MQTT_SESSION_EXPIRY_ID ( 0x11 )
+
+/**
+* @brief Receive maximum id.
+*/
+#define MQTT_RECEIVE_MAX_ID ( 0x21 )
+
+/**
+* @brief Maximum packet size id.
+*/
+#define MQTT_MAX_PACKET_SIZE_ID ( 0x27 )
+
+/**
+* @brief Topic alias size id.
+*/
+#define MQTT_TOPIC_ALIAS_MAX_ID ( 0x22 )
+
+/**
+* @brief Request response id.
+*/
+#define MQTT_REQUEST_RESPONSE_ID ( 0x19 )
+
+/**
+* @brief Request problem id.
+*/
+#define MQTT_REQUEST_PROBLEM_ID ( 0x17 )
+
+/**
+* @brief User property id.
+*/
+#define MQTT_USER_PROPERTY_ID ( 0x26 )
+
+/**
+* @brief Authentication method id.
+*/
+#define MQTT_AUTH_METHOD_ID ( 0x15 )
+
+/**
+* @brief Authentication data id.
+*/
+#define MQTT_AUTH_DATA_ID ( 0x16 )
+
+
+/* Publish properties. */
+
+/**
+* @brief Will delay id.
+*/
+#define MQTT_WILL_DELAY_ID ( 0x18 )
+
+/**
+* @brief Payload format id.
+*/
+#define MQTT_PAYLOAD_FORMAT_ID ( 0x01 )
+
+/**
+* @brief Message Expiry id.
+*/
+#define MQTT_MSG_EXPIRY_ID ( 0x02 )
+
+/**
+* @brief Content type id.
+*/
+#define MQTT_CONTENT_TYPE_ID ( 0x03 )
+
+/**
+* @brief Response topic id.
+*/
+#define MQTT_RESPONSE_TOPIC_ID ( 0x08 )
+
+/**
+* @brief Correlation data id.
+*/
+#define MQTT_CORRELATION_DATA_ID ( 0x09 )
+
+/**
+* @brief Topic alias id.
+*/
+#define MQTT_TOPIC_ALIAS_ID ( 0x23 )
+
+
+/* CONNACK PROPERTIES. */
+
+/**
+* @brief Max qos id.
+*/
+#define MQTT_MAX_QOS_ID ( 0x24 )
+
+/**
+* @brief Retain available id.
+*/
+#define MQTT_RETAIN_AVAILABLE_ID ( 0x25 )
+
+/**
+* @brief Assigned client identifier id.
+*/
+#define MQTT_ASSIGNED_CLIENT_ID ( 0x12 )
+
+/**
+* @brief Reason string id.
+*/
+#define MQTT_REASON_STRING_ID ( 0x1F )
+
+/**
+* @brief Wildcard available id.
+*/
+#define MQTT_WILDCARD_ID ( 0x28 )
+
+/**
+* @brief Subscription available id.
+*/
+#define MQTT_SUB_AVAILABLE_ID ( 0x29 )
+
+/**
+* @brief Shared subscription id.
+*/
+#define MQTT_SHARED_SUB_ID ( 0x2A )
+
+/**
+* @brief Server keep alive id.
+*/
+#define MQTT_SERVER_KEEP_ALIVE_ID ( 0x13 )
+
+/**
+* @brief Response information id.
+*/
+
+#define MQTT_RESPONSE_INFO_ID ( 0x1A )
+
+/**
+* @brief Server reference id.
+*/
+#define MQTT_SERVER_REF_ID ( 0x1C )
+
+/**
+* @brief Subscription ID id
+*/
+#define MQTT_SUBSCRIPTION_ID_ID ( 0x0B )
+
/* Structures defined in this file. */
struct MQTTFixedBuffer;
struct MQTTConnectInfo;
@@ -90,7 +242,7 @@ typedef enum MQTTStatus
MQTTNoMemory, /**< A provided buffer was too small. */
MQTTSendFailed, /**< The transport send function failed. */
MQTTRecvFailed, /**< The transport receive function failed. */
- MQTTBadResponse, /**< An invalid packet was received from the server. */
+ MQTTBadResponse, /**< An invalid packet was received from the server. It is recommended that application closes the connection. */
MQTTServerRefused, /**< The server refused a CONNECT or SUBSCRIBE. */
MQTTNoDataAvailable, /**< No data available from the transport interface. */
MQTTIllegalState, /**< An illegal state in the state record. */
@@ -99,13 +251,15 @@ typedef enum MQTTStatus
MQTTNeedMoreBytes, /**< MQTT_ProcessLoop/MQTT_ReceiveLoop has received
incomplete data; it should be called again (probably after
a delay). */
+ MQTTEndOfProperties, /**< End of properties reached while parsing MQTT packet. */
MQTTStatusConnected, /**< MQTT connection is established with the broker. */
MQTTStatusNotConnected, /**< MQTT connection is not established with the broker. */
MQTTStatusDisconnectPending, /**< Transport Interface has failed and MQTT connection needs to be closed. */
MQTTPublishStoreFailed, /**< User provided API to store a copy of outgoing publish for retransmission purposes,
has failed. */
- MQTTPublishRetrieveFailed /**< User provided API to retrieve the copy of a publish while reconnecting
+ MQTTPublishRetrieveFailed, /**< User provided API to retrieve the copy of a publish while reconnecting
with an unclean session has failed. */
+ MQTTEventCallbackFailed /**< Error in the user provided event callback function. */
} MQTTStatus_t;
/**
@@ -156,7 +310,7 @@ typedef struct MQTTConnectInfo
/**
* @brief Length of the client identifier.
*/
- uint16_t clientIdentifierLength;
+ size_t clientIdentifierLength;
/**
* @brief MQTT user name. Set to NULL if not used.
@@ -166,7 +320,7 @@ typedef struct MQTTConnectInfo
/**
* @brief Length of MQTT user name. Set to 0 if not used.
*/
- uint16_t userNameLength;
+ size_t userNameLength;
/**
* @brief MQTT password. Set to NULL if not used.
@@ -176,9 +330,19 @@ typedef struct MQTTConnectInfo
/**
* @brief Length of MQTT password. Set to 0 if not used.
*/
- uint16_t passwordLength;
+ size_t passwordLength;
} MQTTConnectInfo_t;
+/**
+ * @ingroup mqtt_enum_types
+ * @brief Retain Handling types.
+ */
+typedef enum MQTTRetainHandling{
+ retainSendOnSub = 0, /**< Send retained messages at the time of subscription. */
+ retainSendOnSubIfNotPresent = 1, /**< Send retained messages at subscription only if subscription does not currently exist. */
+ retainDoNotSendonSub = 2 /**< Do not send retained messages at the time of subscription. */
+}MQTTRetainHandling_t;
+
/**
* @ingroup mqtt_struct_types
* @brief MQTT SUBSCRIBE packet parameters.
@@ -186,7 +350,7 @@ typedef struct MQTTConnectInfo
typedef struct MQTTSubscribeInfo
{
/**
- * @brief Quality of Service for subscription.
+ * @brief Quality of Service for subscription. Include protocol error of qos > 2
*/
MQTTQoS_t qos;
@@ -196,9 +360,31 @@ typedef struct MQTTSubscribeInfo
const char * pTopicFilter;
/**
- * @brief Length of subscription topic filter.
+ * @brief Length of subscription topic filter - unsigned long
+ */
+ size_t topicFilterLength;
+ /**
+ * @brief no local option for subscription. Include protocol error if noLocalOption = 1 in a shared subscription
+ */
+
+ /**
+ * @brief If true, Application Messages that are published to this subscription
+ * will not be forwarded to the Client that published them.
+ */
+ bool noLocalOption;
+
+ /**
+ * @brief If true, Application Messages forwarded using this subscription keep the RETAIN
+ * flag they were published with.
+ */
+ bool retainAsPublishedOption;
+
+ /**
+ * @brief Specifies whether retained messages are sent
+ * when the subscription is established.
*/
- uint16_t topicFilterLength;
+ MQTTRetainHandling_t retainHandlingOption;
+
} MQTTSubscribeInfo_t;
/**
@@ -230,7 +416,7 @@ typedef struct MQTTPublishInfo
/**
* @brief Length of topic name.
*/
- uint16_t topicNameLength;
+ size_t topicNameLength;
/**
* @brief Message payload.
@@ -241,6 +427,12 @@ typedef struct MQTTPublishInfo
* @brief Message payload length.
*/
size_t payloadLength;
+
+ /**
+ * @brief Length of the properties.
+ */
+ size_t propertyLength;
+
} MQTTPublishInfo_t;
/**
@@ -271,11 +463,277 @@ typedef struct MQTTPacketInfo
} MQTTPacketInfo_t;
/**
- * @brief Get the size and Remaining Length of an MQTT CONNECT packet.
+ * @ingroup mqtt_struct_types
+ * @brief Property builder for MQTT packets.
+ */
+typedef struct MQTTPropBuilder
+{
+ uint8_t * pBuffer; /**< @brief Pointer to the buffer for storing properties. */
+ size_t bufferLength; /**< @brief Total length of the buffer available for properties. */
+ size_t currentIndex; /**< @brief Current position in the buffer where next property will be written. */
+ uint32_t fieldSet; /**< @brief Bitfield tracking which properties have been added. */
+} MQTTPropBuilder_t;
+
+ /**
+ * @ingroup mqtt_struct_types
+ * @brief Struct to hold reason codes.
+ */
+typedef struct MQTTReasonCodeInfo
+{
+ /** @brief Pointer to the reason code array. */
+ const uint8_t * reasonCode;
+
+ /** @brief Length of the reason code array. */
+ size_t reasonCodeLength;
+
+} MQTTReasonCodeInfo_t;
+
+/**
+* @ingroup mqtt_struct_types
+* @brief Struct to hold connect and connack properties.
+*/
+typedef struct MQTTConnectProperties
+{
+ /**
+ * @brief Four Byte Integer representing the Session Expiry Interval in seconds.
+ */
+ uint32_t sessionExpiry;
+
+ /**
+ * @brief Maximum number of unacknowledged PUBLISH packets client is willing to receive.
+ */
+ uint16_t receiveMax;
+
+ /**
+ * @brief Four Byte Integer representing the Maximum Packet Size the Client is willing to accept.
+ */
+ uint32_t maxPacketSize;
+
+ /**
+ * @brief Two Byte Integer representing the Topic Alias Maximum value.
+ */
+ uint16_t topicAliasMax;
+
+ /**
+ * @brief A value of 0 indicates that the Server MUST NOT return Response Information.
+ */
+ bool requestResponseInfo;
+
+ /**
+ * @brief The Client uses this value to indicate whether the Reason String or User Properties
+ * are sent in the case of failures
+ */
+ bool requestProblemInfo;
+
+ /**
+ * @brief Maximum number of unacknowledged PUBLISH packets server is willing to receive.
+ */
+ uint16_t serverReceiveMax;
+
+ /**
+ * @brief Max qos supported by the server.
+ */
+ uint8_t serverMaxQos;
+
+ /**
+ * @brief Byte declares whether the Server supports retained messages.
+ */
+ uint8_t retainAvailable;
+
+ /**
+ * @brief Four Byte Integer representing the Maximum Packet Size the Server is willing to accept.
+ */
+ uint32_t serverMaxPacketSize;
+
+ /**
+ * @brief Two Byte Integer representing the Topic Alias Maximum value.
+ */
+ uint16_t serverTopicAliasMax;
+
+ /**
+ * @brief Whether wildcard subscription is available.
+ */
+ uint8_t isWildcardAvailable;
+
+ /**
+ * @brief Whether the Server supports Subscription Identifiers.
+ */
+ uint8_t isSubscriptionIdAvailable;
+
+ /**
+ * @brief Whether the Server supports Shared Subscription.
+ */
+ uint8_t isSharedAvailable;
+
+ /**
+ * @brief Keep Alive value given by the server.
+ */
+ uint16_t serverKeepAlive;
+
+
+} MQTTConnectionProperties_t;
+
+/**
+ * @ingroup mqtt_enum_types
+ * @brief MQTT reason codes.
+ *
+ * These values are defined in the MQTT 5.0 specification.
+ */
+typedef enum MQTTSuccessFailReasonCode
+{
+ /* PUBACK reason codes */
+ MQTT_REASON_PUBACK_SUCCESS = 0x00, /**< Publish was successfully received and accepted. */
+ MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS = 0x10, /**< Publish was accepted but there are no subscribers. */
+ MQTT_REASON_PUBACK_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred for the PUBACK. */
+ MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error for the PUBACK. */
+ MQTT_REASON_PUBACK_NOT_AUTHORIZED = 0x87, /**< Client is not authorized to publish. */
+ MQTT_REASON_PUBACK_TOPIC_NAME_INVALID = 0x90, /**< Topic name is not valid. */
+ MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE = 0x91, /**< Packet identifier is already in use. */
+ MQTT_REASON_PUBACK_QUOTA_EXCEEDED = 0x97, /**< Implementation or system quota exceeded. */
+ MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID = 0x99, /**< Payload format is invalid. */
+
+ /* PUBREC reason codes */
+ MQTT_REASON_PUBREC_SUCCESS = 0x00, /**< Publish was successfully received for QoS 2. */
+ MQTT_REASON_PUBREC_NO_MATCHING_SUBSCRIBERS = 0x10, /**< Publish received but no matching subscribers. */
+ MQTT_REASON_PUBREC_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred for the PUBREC. */
+ MQTT_REASON_PUBREC_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error for the PUBREC. */
+ MQTT_REASON_PUBREC_NOT_AUTHORIZED = 0x87, /**< Client is not authorized to publish. */
+ MQTT_REASON_PUBREC_TOPIC_NAME_INVALID = 0x90, /**< Topic name is not valid. */
+ MQTT_REASON_PUBREC_PACKET_IDENTIFIER_IN_USE = 0x91, /**< Packet identifier is already in use. */
+ MQTT_REASON_PUBREC_QUOTA_EXCEEDED = 0x97, /**< Implementation or system quota exceeded. */
+ MQTT_REASON_PUBREC_PAYLOAD_FORMAT_INVALID = 0x99, /**< Payload format is invalid. */
+
+ /* PUBREL reason codes */
+ MQTT_REASON_PUBREL_SUCCESS = 0x00, /**< Publish release was successful. */
+ MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND = 0x92, /**< Packet identifier was not found. */
+
+ /* PUBCOMP reason codes */
+ MQTT_REASON_PUBCOMP_SUCCESS = 0x00, /**< Publish complete was successful. */
+ MQTT_REASON_PUBCOMP_PACKET_IDENTIFIER_NOT_FOUND = 0x92, /**< Packet identifier was not found. */
+
+ /* CONNACK reason codes */
+ MQTT_REASON_CONNACK_SUCCESS = 0x00, /**< Connection accepted. */
+ MQTT_REASON_CONNACK_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred during connection. */
+ MQTT_REASON_CONNACK_MALFORMED_PACKET = 0x81, /**< Received packet was malformed. */
+ MQTT_REASON_CONNACK_PROTOCOL_ERROR = 0x82, /**< Protocol error occurred. */
+ MQTT_REASON_CONNACK_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error. */
+ MQTT_REASON_CONNACK_UNSUPPORTED_PROTOCOL_VERSION = 0x84, /**< Protocol version not supported. */
+ MQTT_REASON_CONNACK_CLIENT_IDENTIFIER_NOT_VALID = 0x85, /**< Client identifier is not valid. */
+ MQTT_REASON_CONNACK_BAD_USER_NAME_OR_PASSWORD = 0x86, /**< Username or password is malformed. */
+ MQTT_REASON_CONNACK_NOT_AUTHORIZED = 0x87, /**< Client is not authorized to connect. */
+ MQTT_REASON_CONNACK_SERVER_UNAVAILABLE = 0x88, /**< Server is unavailable. */
+ MQTT_REASON_CONNACK_SERVER_BUSY = 0x89, /**< Server is busy. */
+ MQTT_REASON_CONNACK_BANNED = 0x8A, /**< Client has been banned. */
+ MQTT_REASON_CONNACK_BAD_AUTHENTICATION_METHOD = 0x8C, /**< Authentication method is not supported. */
+ MQTT_REASON_CONNACK_TOPIC_NAME_INVALID = 0x90, /**< Topic name is invalid. */
+ MQTT_REASON_CONNACK_PACKET_TOO_LARGE = 0x95, /**< Packet size exceeds maximum allowed. */
+ MQTT_REASON_CONNACK_QUOTA_EXCEEDED = 0x97, /**< Implementation or system quota exceeded. */
+ MQTT_REASON_CONNACK_PAYLOAD_FORMAT_INVALID = 0x99, /**< Payload format is invalid. */
+ MQTT_REASON_CONNACK_RETAIN_NOT_SUPPORTED = 0x9A, /**< Retain is not supported. */
+ MQTT_REASON_CONNACK_QOS_NOT_SUPPORTED = 0x9B, /**< QoS level is not supported. */
+ MQTT_REASON_CONNACK_USE_ANOTHER_SERVER = 0x9C, /**< Client should temporarily use another server. */
+ MQTT_REASON_CONNACK_SERVER_MOVED = 0x9D, /**< Client should permanently use another server. */
+ MQTT_REASON_CONNACK_CONNECTION_RATE_EXCEEDED = 0x9F, /**< Connection rate limit exceeded. */
+
+ /* SUBACK reason codes */
+ MQTT_REASON_SUBACK_GRANTED_QOS0 = 0x00, /**< Subscription accepted with maximum QoS 0. */
+ MQTT_REASON_SUBACK_GRANTED_QOS1 = 0x01, /**< Subscription accepted with maximum QoS 1. */
+ MQTT_REASON_SUBACK_GRANTED_QOS2 = 0x02, /**< Subscription accepted with maximum QoS 2. */
+ MQTT_REASON_SUBACK_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred for the subscription. */
+ MQTT_REASON_SUBACK_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error. */
+ MQTT_REASON_SUBACK_NOT_AUTHORIZED = 0x87, /**< Client is not authorized to subscribe. */
+ MQTT_REASON_SUBACK_TOPIC_FILTER_INVALID = 0x8F, /**< Topic filter is not valid. */
+ MQTT_REASON_SUBACK_PACKET_IDENTIFIER_IN_USE = 0x91, /**< Packet identifier is already in use. */
+ MQTT_REASON_SUBACK_QUOTA_EXCEEDED = 0x97, /**< Implementation or system quota exceeded. */
+ MQTT_REASON_SUBACK_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 0x9E, /**< Shared subscriptions are not supported. */
+ MQTT_REASON_SUBACK_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 0xA1, /**< Subscription identifiers are not supported. */
+ MQTT_REASON_SUBACK_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xA2, /**< Wildcard subscriptions are not supported. */
+
+ /* UNSUBACK reason codes */
+ MQTT_REASON_UNSUBACK_SUCCESS = 0x00, /**< Unsubscribe was successful. */
+ MQTT_REASON_UNSUBACK_NO_SUBSCRIPTION_EXISTED = 0x11, /**< No matching subscription existed. */
+ MQTT_REASON_UNSUBACK_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred for the unsubscribe. */
+ MQTT_REASON_UNSUBACK_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error. */
+ MQTT_REASON_UNSUBACK_NOT_AUTHORIZED = 0x87, /**< Client is not authorized to unsubscribe. */
+ MQTT_REASON_UNSUBACK_TOPIC_FILTER_INVALID = 0x8F, /**< Topic filter is not valid. */
+ MQTT_REASON_UNSUBACK_PACKET_IDENTIFIER_IN_USE = 0x91, /**< Packet identifier is already in use. */
+
+ /* DISCONNECT reason codes */
+ MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION = 0x00, /**< Normal client-initiated disconnect. */
+ MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE = 0x04, /**< Client disconnecting with Will Message. */
+ MQTT_REASON_DISCONNECT_UNSPECIFIED_ERROR = 0x80, /**< Unspecified error occurred. */
+ MQTT_REASON_DISCONNECT_MALFORMED_PACKET = 0x81, /**< Received packet was malformed. */
+ MQTT_REASON_DISCONNECT_PROTOCOL_ERROR = 0x82, /**< Protocol error occurred. */
+ MQTT_REASON_DISCONNECT_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, /**< Implementation specific error. */
+ MQTT_REASON_DISCONNECT_NOT_AUTHORIZED = 0x87, /**< Client is not authorized. */
+ MQTT_REASON_DISCONNECT_SERVER_BUSY = 0x89, /**< Server is busy. */
+ MQTT_REASON_DISCONNECT_SERVER_SHUTTING_DOWN = 0x8B, /**< Server is shutting down. */
+ MQTT_REASON_DISCONNECT_BAD_AUTHENTICATION_METHOD = 0x8C, /**< Authentication method is invalid. */
+ MQTT_REASON_DISCONNECT_KEEP_ALIVE_TIMEOUT = 0x8D, /**< Keep alive timeout occurred. */
+ MQTT_REASON_DISCONNECT_SESSION_TAKEN_OVER = 0x8E, /**< Another connection using same client ID. */
+ MQTT_REASON_DISCONNECT_TOPIC_FILTER_INVALID = 0x8F, /**< Topic filter is not valid. */
+ MQTT_REASON_DISCONNECT_TOPIC_NAME_INVALID = 0x90, /**< Topic name is not valid. */
+ MQTT_REASON_DISCONNECT_RECEIVE_MAXIMUM_EXCEEDED = 0x93, /**< Receive maximum value exceeded. */
+ MQTT_REASON_DISCONNECT_TOPIC_ALIAS_INVALID = 0x94, /**< Topic alias is invalid. */
+ MQTT_REASON_DISCONNECT_PACKET_TOO_LARGE = 0x95, /**< Packet size exceeds maximum allowed. */
+ MQTT_REASON_DISCONNECT_MESSAGE_RATE_TOO_HIGH = 0x96, /**< Message rate too high. */
+ MQTT_REASON_DISCONNECT_QUOTA_EXCEEDED = 0x97, /**< Implementation or system quota exceeded. */
+ MQTT_REASON_DISCONNECT_ADMINISTRATIVE_ACTION = 0x98, /**< Disconnected due to administrative action. */
+ MQTT_REASON_DISCONNECT_PAYLOAD_FORMAT_INVALID = 0x99, /**< Payload format is invalid. */
+ MQTT_REASON_DISCONNECT_RETAIN_NOT_SUPPORTED = 0x9A, /**< Retain is not supported. */
+ MQTT_REASON_DISCONNECT_QOS_NOT_SUPPORTED = 0x9B, /**< QoS level is not supported. */
+ MQTT_REASON_DISCONNECT_USE_ANOTHER_SERVER = 0x9C, /**< Client should temporarily use another server. */
+ MQTT_REASON_DISCONNECT_SERVER_MOVED = 0x9D, /**< Client should permanently use another server. */
+ MQTT_REASON_DISCONNECT_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 0x9E, /**< Shared subscriptions are not supported. */
+ MQTT_REASON_DISCONNECT_CONNECTION_RATE_EXCEEDED = 0x9F, /**< Connection rate limit exceeded. */
+ MQTT_REASON_DISCONNECT_MAXIMUM_CONNECT_TIME = 0xA0, /**< Maximum connection time authorized exceeded. */
+ MQTT_REASON_DISCONNECT_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 0xA1, /**< Subscription identifiers are not supported. */
+ MQTT_REASON_DISCONNECT_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xA2, /**< Wildcard subscriptions are not supported. */
+
+ MQTT_INVALID_REASON_CODE = 0xFF /**< @brief Invalid reason code. */
+
+} MQTTSuccessFailReasonCode_t;
+
+/**
+* @ingroup mqtt_struct_types
+* @brief Struct to hold user property.
+*/
+typedef struct MQTTUserProperty
+{
+ /**
+ * @brief key.
+ */
+ const char * pKey;
+ /**
+ * @brief Length of the key.
+ */
+ size_t keyLength;
+ /**
+ * @brief value.
+ */
+ const char * pValue;
+ /**
+ * @brief Length of the value.
+ */
+ size_t valueLength;
+} MQTTUserProperty_t;
+
+/**
+ * @ingroup mqtt_enum_types
+ * @brief MQTT Subscription packet types.
+ */
+typedef enum MQTTSubscriptionType
+{
+ MQTT_TYPE_SUBSCRIBE, /**< @brief The type is a SUBSCRIBE packet. */
+ MQTT_TYPE_UNSUBSCRIBE /**< @brief The type is a UNSUBSCRIBE packet. */
+} MQTTSubscriptionType_t;
+
+/**
+ * @brief Get the size and Remaining Length of an MQTT Version 5 CONNECT packet.
*
* This function must be called before #MQTT_SerializeConnect in order to get
- * the size of the MQTT CONNECT packet that is generated from #MQTTConnectInfo_t
- * and optional #MQTTPublishInfo_t. The size of the #MQTTFixedBuffer_t supplied
+ * the size of the MQTT CONNECT packet that is generated from #MQTTConnectInfo_t, #MQTTPublishInfo_t
+ * and optional MQTTPropBuilder_t. The size of the #MQTTFixedBuffer_t supplied
* to #MQTT_SerializeConnect must be at least @p pPacketSize. The provided
* @p pConnectInfo and @p pWillInfo are valid for serialization with
* #MQTT_SerializeConnect only if this function returns #MQTTSuccess. The
@@ -284,6 +742,8 @@ typedef struct MQTTPacketInfo
*
* @param[in] pConnectInfo MQTT CONNECT packet parameters.
* @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[in] pConnectProperties MQTT CONNECT properties builder. Pass NULL if not used.
+ * @param[in] pWillProperties MQTT Will properties builder. Pass NULL if not used.
* @param[out] pRemainingLength The Remaining Length of the MQTT CONNECT packet.
* @param[out] pPacketSize The total size of the MQTT CONNECT packet.
*
@@ -297,6 +757,8 @@ typedef struct MQTTPacketInfo
* MQTTStatus_t status;
* MQTTConnectInfo_t connectInfo = { 0 };
* MQTTPublishInfo_t willInfo = { 0 };
+ * MQTTPropBuilder_t connectionProperties = { 0 };
+ * MQTTPropBuilder_t willProperties = { 0 };
* size_t remainingLength = 0, packetSize = 0;
*
* // Initialize the connection info, the details are out of scope for this example.
@@ -305,9 +767,18 @@ typedef struct MQTTPacketInfo
* // Initialize the optional will info, the details are out of scope for this example.
* initializeWillInfo( &willInfo );
*
+ * // Initialize connect properties and will properties, the details are out of scope for this example.
+ * initializeConnectProperties( &connectionProperties );
+ * initializeWillProperties( &willProperties );
+ *
* // Get the size requirement for the connect packet.
* status = MQTT_GetConnectPacketSize(
- * &connectInfo, &willInfo, &remainingLength, &packetSize
+ * &connectInfo,
+ * &willInfo,
+ * &connectionProperties,
+ * &willProperties,
+ * &remainingLength,
+ * &packetSize
* );
*
* if( status == MQTTSuccess )
@@ -320,21 +791,26 @@ typedef struct MQTTPacketInfo
/* @[declare_mqtt_getconnectpacketsize] */
MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize );
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize );
/* @[declare_mqtt_getconnectpacketsize] */
/**
* @brief Serialize an MQTT CONNECT packet in the given fixed buffer @p pFixedBuffer.
*
- * #MQTT_GetConnectPacketSize should be called with @p pConnectInfo and
- * @p pWillInfo before invoking this function to get the size of the required
- * #MQTTFixedBuffer_t and @p remainingLength. The @p remainingLength must be
- * the same as returned by #MQTT_GetConnectPacketSize. The #MQTTFixedBuffer_t
- * must be at least as large as the size returned by #MQTT_GetConnectPacketSize.
+ * #MQTT_GetConnectPacketSize should be called with @p pConnectInfo, @p pWillInfo,
+ * @p pConnectProperties, and @p pWillProperties before invoking this function to get
+ * the size of the required #MQTTFixedBuffer_t and @p remainingLength. The
+ * @p remainingLength must be the same as returned by #MQTT_GetConnectPacketSize.
+ * The #MQTTFixedBuffer_t must be at least as large as the size returned by
+ * #MQTT_GetConnectPacketSize.
*
* @param[in] pConnectInfo MQTT CONNECT packet parameters.
* @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
+ * @param[in] pConnectProperties MQTT CONNECT properties builder. Pass NULL if not used.
+ * @param[in] pWillProperties MQTT Will properties builder. Pass NULL if not used.
* @param[in] remainingLength Remaining Length provided by #MQTT_GetConnectPacketSize.
* @param[out] pFixedBuffer Buffer for packet serialization.
*
@@ -349,6 +825,8 @@ MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
* MQTTStatus_t status;
* MQTTConnectInfo_t connectInfo = { 0 };
* MQTTPublishInfo_t willInfo = { 0 };
+ * MQTTPropBuilder_t connectionProperties = { 0 };
+ * MQTTPropBuilder_t willProperties = { 0 };
* MQTTFixedBuffer_t fixedBuffer;
* uint8_t buffer[ BUFFER_SIZE ];
* size_t remainingLength = 0, packetSize = 0;
@@ -356,16 +834,24 @@ MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
* fixedBuffer.pBuffer = buffer;
* fixedBuffer.size = BUFFER_SIZE;
*
- * // Assume connectInfo and willInfo are initialized. Get the size requirement for
- * // the connect packet.
+ * // Assume connectInfo, willInfo, and properties are initialized.
+ * // Get the size requirement for the connect packet.
* status = MQTT_GetConnectPacketSize(
- * &connectInfo, &willInfo, &remainingLength, &packetSize
+ * &connectInfo, &willInfo, &connectionProperties, &willProperties,
+ * &remainingLength, &packetSize
* );
* assert( status == MQTTSuccess );
* assert( packetSize <= BUFFER_SIZE );
*
* // Serialize the connect packet into the fixed buffer.
- * status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ * status = MQTT_SerializeConnect(
+ * &connectInfo,
+ * &willInfo,
+ * &connectionProperties,
+ * &willProperties,
+ * remainingLength,
+ * &fixedBuffer
+ * );
*
* if( status == MQTTSuccess )
* {
@@ -376,7 +862,9 @@ MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
/* @[declare_mqtt_serializeconnect] */
MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
+ const MQTTPropBuilder_t * pConnectProperties,
+ const MQTTPropBuilder_t * pWillProperties,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_serializeconnect] */
@@ -385,17 +873,20 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
*
* This function must be called before #MQTT_SerializeSubscribe in order to get
* the size of the MQTT SUBSCRIBE packet that is generated from the list of
- * #MQTTSubscribeInfo_t. The size of the #MQTTFixedBuffer_t supplied
- * to #MQTT_SerializeSubscribe must be at least @p pPacketSize. The provided
- * @p pSubscriptionList is valid for serialization with #MQTT_SerializeSubscribe
+ * #MQTTSubscribeInfo_t and #MQTTPropBuilder_t (optional subscribe properties).
+ * The size of the #MQTTFixedBuffer_t supplied to #MQTT_SerializeSubscribe must
+ * be at least @p pPacketSize. The provided @p pSubscriptionList is valid for
+ * serialization with #MQTT_SerializeSubscribe
* only if this function returns #MQTTSuccess. The remaining length returned in
* @p pRemainingLength and the packet size returned in @p pPacketSize are valid
* only if this function returns #MQTTSuccess.
*
* @param[in] pSubscriptionList List of MQTT subscription info.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] pSubscribeProperties MQTT SUBSCRIBE properties builder. Pass NULL if not used.
* @param[out] pRemainingLength The Remaining Length of the MQTT SUBSCRIBE packet.
* @param[out] pPacketSize The total size of the MQTT SUBSCRIBE packet.
+ * @param[in] maxPacketSize Maximum packet size.
*
* @return #MQTTBadParameter if the packet would exceed the size allowed by the
* MQTT spec; #MQTTSuccess otherwise.
@@ -406,6 +897,7 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * MQTTPropBuilder_t subscribeProperties = { 0 };
* size_t remainingLength = 0, packetSize = 0;
* // This is assumed to be a list of filters we want to subscribe to.
* const char * filters[ NUMBER_OF_SUBSCRIPTIONS ];
@@ -417,11 +909,22 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
* // Each subscription needs a topic filter.
* subscriptionList[ i ].pTopicFilter = filters[ i ];
* subscriptionList[ i ].topicFilterLength = strlen( filters[ i ] );
+ * subscriptionList[ i ].noLocalOption = false;
+ * subscriptionList[ i ].retainAsPublishedOption = false;
+ * subscriptionList[ i ].retainHandlingOption = retainSendOnSub;
* }
*
+ * // Initialize subscribe properties (if needed)
+ * initializeSubscribeProperties( &subscribeProperties );
+ *
* // Get the size requirement for the subscribe packet.
* status = MQTT_GetSubscribePacketSize(
- * &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * &subscriptionList[ 0 ],
+ * NUMBER_OF_SUBSCRIPTIONS,
+ * &subscribeProperties,
+ * &remainingLength,
+ * &packetSize,
+ * maxPacketSize
* );
*
* if( status == MQTTSuccess )
@@ -434,8 +937,10 @@ MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
/* @[declare_mqtt_getsubscribepacketsize] */
MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize );
+ const MQTTPropBuilder_t * pSubscribeProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize );
/* @[declare_mqtt_getsubscribepacketsize] */
/**
@@ -449,6 +954,8 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
*
* @param[in] pSubscriptionList List of MQTT subscription info.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] pSubscribeProperties MQTT v5.0 properties for the SUBSCRIBE packet. Can be NULL
+ * if no properties are needed.
* @param[in] packetId packet ID generated by #MQTT_GetPacketId.
* @param[in] remainingLength Remaining Length provided by #MQTT_GetSubscribePacketSize.
* @param[out] pFixedBuffer Buffer for packet serialization.
@@ -463,6 +970,7 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * MQTTPropBuilder_t subscribeProperties = { 0 };
* MQTTFixedBuffer_t fixedBuffer;
* uint8_t buffer[ BUFFER_SIZE ];
* size_t remainingLength = 0, packetSize = 0;
@@ -475,9 +983,11 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
* // scope for this example.
* packetId = getNewPacketId();
*
- * // Assume subscriptionList has been initialized. Get the subscribe packet size.
+ * // Assume subscriptionList and subscribeProperties have been initialized.
+ * Get the subscribe packet size.
* status = MQTT_GetSubscribePacketSize(
- * &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &subscribeProperties,
+ * &remainingLength, &packetSize
* );
* assert( status == MQTTSuccess );
* assert( packetSize <= BUFFER_SIZE );
@@ -486,6 +996,7 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
* status = MQTT_SerializeSubscribe(
* &subscriptionList[ 0 ],
* NUMBER_OF_SUBSCRIPTIONS,
+ * &subscribeProperties,
* packetId,
* remainingLength,
* &fixedBuffer
@@ -500,8 +1011,9 @@ MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscript
/* @[declare_mqtt_serializesubscribe] */
MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
+ const MQTTPropBuilder_t * pSubscribeProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_serializesubscribe] */
@@ -510,17 +1022,19 @@ MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionL
*
* This function must be called before #MQTT_SerializeUnsubscribe in order to
* get the size of the MQTT UNSUBSCRIBE packet that is generated from the list
- * of #MQTTSubscribeInfo_t. The size of the #MQTTFixedBuffer_t supplied
- * to #MQTT_SerializeUnsubscribe must be at least @p pPacketSize. The provided
- * @p pSubscriptionList is valid for serialization with #MQTT_SerializeUnsubscribe
- * only if this function returns #MQTTSuccess. The remaining length returned in
- * @p pRemainingLength and the packet size returned in @p pPacketSize are valid
- * only if this function returns #MQTTSuccess.
+ * of #MQTTSubscribeInfo_t and #MQTTPropBuilder_t (optional unsubscribe properties).
+ * The size of the #MQTTFixedBuffer_t supplied to #MQTT_SerializeUnsubscribe must be
+ * at least @p pPacketSize. The provided @p pSubscriptionList is valid for serialization
+ * with #MQTT_SerializeUnsubscribe only if this function returns #MQTTSuccess.
+ * The remaining length returned in @p pRemainingLength and the packet size returned
+ * in @p pPacketSize are valid only if this function returns #MQTTSuccess.
*
* @param[in] pSubscriptionList List of MQTT subscription info.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
+ * @param[in] pUnsubscribeProperties MQTT UNSUBSCRIBE properties builder. Pass NULL if not used.
* @param[out] pRemainingLength The Remaining Length of the MQTT UNSUBSCRIBE packet.
* @param[out] pPacketSize The total size of the MQTT UNSUBSCRIBE packet.
+ * @param[in] maxPacketSize Maximum packet size.
*
* @return #MQTTBadParameter if the packet would exceed the size allowed by the
* MQTT spec; #MQTTSuccess otherwise.
@@ -532,111 +1046,140 @@ MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionL
* MQTTStatus_t status;
* MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
* size_t remainingLength = 0, packetSize = 0;
+ * MQTTPropBuilder_t unsubscribeProperties = { 0 };
+ * size_t maxPacketSize = 0;
+ *
+ * // Initialize maxPacketSize. The details are out of scope for this example.
+ * initializeMaxPacketSize( &maxPacketSize );
*
* // Initialize the subscribe info. The details are out of scope for this example.
* initializeSubscribeInfo( &subscriptionList[ 0 ] );
*
+ * //Initialize the property buffer. The details are out of scope for this example.
+ * initializePropertyBuffer( &unsubscribeProperties );
+ *
* // Get the size requirement for the unsubscribe packet.
* status = MQTT_GetUnsubscribePacketSize(
- * &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
- * );
+ * &subscriptionList[ 0 ],
+ * NUMBER_OF_SUBSCRIPTIONS,
+ * &unsubscribeProperties,
+ * &remainingLength,
+ * &packetSize,
+ * maxPacketSize);
*
* if( status == MQTTSuccess )
* {
- * // The application should allocate or use a static #MQTTFixedBuffer_t
- * // of size >= packetSize to serialize the unsubscribe request.
+ * // The unsubscribe packet can now be sent to the broker.
* }
* @endcode
*/
/* @[declare_mqtt_getunsubscribepacketsize] */
MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize );
+ const MQTTPropBuilder_t * pUnsubscribeProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize );
/* @[declare_mqtt_getunsubscribepacketsize] */
/**
- * @brief Serialize an MQTT UNSUBSCRIBE packet in the given buffer.
+ * @brief Serialize an MQTT UNSUBSCRIBE packet with properties in the given buffer.
*
* #MQTT_GetUnsubscribePacketSize should be called with @p pSubscriptionList
- * before invoking this function to get the size of the required
+ * and @p pUnsubscribeProperties before invoking this function to get the size of the required
* #MQTTFixedBuffer_t and @p remainingLength. The @p remainingLength must be
* the same as returned by #MQTT_GetUnsubscribePacketSize. The #MQTTFixedBuffer_t
* must be at least as large as the size returned by #MQTT_GetUnsubscribePacketSize.
*
- * @param[in] pSubscriptionList List of MQTT subscription info.
+ * @param[in] pSubscriptionList List of MQTT subscription info to unsubscribe from.
* @param[in] subscriptionCount The number of elements in pSubscriptionList.
- * @param[in] packetId packet ID generated by #MQTT_GetPacketId.
+ * @param[in] pUnsubscribeProperties MQTT 5.0 properties for the UNSUBSCRIBE packet. Can be NULL if no properties are needed.
+ * @param[in] packetId Packet identifier used for the UNSUBSCRIBE packet.
* @param[in] remainingLength Remaining Length provided by #MQTT_GetUnsubscribePacketSize.
- * @param[out] pFixedBuffer Buffer for packet serialization.
+ * @param[out] pFixedBuffer Buffer where the serialized UNSUBSCRIBE packet will be written.
*
* @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSuccess otherwise.
+ * #MQTTBadParameter if any of the parameters are invalid (NULL pSubscriptionList or pFixedBuffer, zero subscriptionCount);
+ * #MQTTSuccess if the packet was serialized successfully.
*
* Example
* @code{c}
*
* // Variables used in this example.
* MQTTStatus_t status;
- * MQTTSubscribeInfo_t subscriptionList[ NUMBER_OF_SUBSCRIPTIONS ] = { 0 };
+ * MQTTSubscribeInfo_t subscriptionList[2];
+ * MQTTPropBuilder_t unsubscribeProperties;
* MQTTFixedBuffer_t fixedBuffer;
- * uint8_t buffer[ BUFFER_SIZE ];
+ * uint8_t buffer[100];
* size_t remainingLength = 0, packetSize = 0;
- * uint16_t packetId;
+ * uint16_t packetId = 1;
*
+ * // Initialize the fixed buffer.
* fixedBuffer.pBuffer = buffer;
- * fixedBuffer.size = BUFFER_SIZE;
+ * fixedBuffer.size = sizeof( buffer );
*
- * // Function to return a valid, unused packet identifier. The details are out of
- * // scope for this example.
- * packetId = getNewPacketId();
+ * // Initialize subscription list.
+ * subscriptionList[0].pTopicFilter = "topic/1";
+ * subscriptionList[0].topicFilterLength = strlen("topic/1");
+ * subscriptionList[1].pTopicFilter = "topic/2";
+ * subscriptionList[1].topicFilterLength = strlen("topic/2");
*
- * // Assume subscriptionList has been initialized. Get the unsubscribe packet size.
+ * // Initialize properties (optional)
+ *
+ * // Get size requirement for the unsubscribe packet.
* status = MQTT_GetUnsubscribePacketSize(
- * &subscriptionList[ 0 ], NUMBER_OF_SUBSCRIPTIONS, &remainingLength, &packetSize
+ * subscriptionList,
+ * 2,
+ * &unsubscribeProperties,
+ * &remainingLength,
+ * &packetSize
* );
- * assert( status == MQTTSuccess );
- * assert( packetSize <= BUFFER_SIZE );
*
- * // Serialize the unsubscribe packet into the fixed buffer.
- * status = MQTT_SerializeUnsubscribe(
- * &subscriptionList[ 0 ],
- * NUMBER_OF_SUBSCRIPTIONS,
- * packetId,
- * remainingLength,
- * &fixedBuffer
- * );
+ * if( status == MQTTSuccess )
+ * {
+ * // Serialize unsubscribe packet.
+ * status = MQTT_SerializeUnsubscribe(
+ * subscriptionList,
+ * 2,
+ * &unsubscribeProperties,
+ * packetId,
+ * remainingLength,
+ * &fixedBuffer
+ * );
+ * }
*
* if( status == MQTTSuccess )
* {
- * // The unsubscribe packet can now be sent to the broker.
+ * // The unsubscribe packet has been serialized successfully.
+ * // The serialized packet is now ready to be sent to the broker.
* }
+ *
* @endcode
*/
/* @[declare_mqtt_serializeunsubscribe] */
MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount,
+ const MQTTPropBuilder_t * pUnsubscribeProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_serializeunsubscribe] */
/**
* @brief Get the packet size and remaining length of an MQTT PUBLISH packet.
*
- * This function must be called before #MQTT_SerializePublish in order to get
- * the size of the MQTT PUBLISH packet that is generated from #MQTTPublishInfo_t.
- * The size of the #MQTTFixedBuffer_t supplied to #MQTT_SerializePublish must be
- * at least @p pPacketSize. The provided @p pPublishInfo is valid for
- * serialization with #MQTT_SerializePublish only if this function returns
- * #MQTTSuccess. The remaining length returned in @p pRemainingLength and the
+ * #MQTT_ValidatePublishParams should be called with @p pPublishInfo before invoking this function
+ * to validate the publish parameters. This function must be called before #sendPublishWithoutCopy
+ * in order to get the size of the MQTT PUBLISH packet that is generated from #MQTTPublishInfo_t
+ * and optional publish properties. The remaining length returned in @p pRemainingLength and the
* packet size returned in @p pPacketSize are valid only if this function
* returns #MQTTSuccess.
*
* @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] pPublishProperties MQTT PUBLISH properties builder. Pass NULL if not used.
* @param[out] pRemainingLength The Remaining Length of the MQTT PUBLISH packet.
* @param[out] pPacketSize The total size of the MQTT PUBLISH packet.
+ * @param[in] maxPacketSize Maximum packet size allowed by the server.
*
* @return #MQTTBadParameter if the packet would exceed the size allowed by the
* MQTT spec or if invalid parameters are passed; #MQTTSuccess otherwise.
@@ -647,6 +1190,10 @@ MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptio
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTPropBuilder_t publishProperties = { 0 };
+ * uint16_t topicAliasMax;
+ * uint8_t retainAvailable;
+ * uint8_t maxQos;
* size_t remainingLength = 0, packetSize = 0;
*
* // Initialize the publish info.
@@ -656,22 +1203,33 @@ MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptio
* publishInfo.pPayload = "Hello World!";
* publishInfo.payloadLength = strlen( "Hello World!" );
*
+ * // Initialize publish properties (if needed)
+ * initializePublishProperties( &publishProperties );
+ *
+ * // Validate publish parameters
+ * status = MQTT_ValidatePublishParams(&publishInfo, topicAliasMax, retainAvailable, maxQos);
+ *
* // Get the size requirement for the publish packet.
* status = MQTT_GetPublishPacketSize(
- * &publishInfo, &remainingLength, &packetSize
+ * &publishInfo,
+ * &publishProperties,
+ * &remainingLength,
+ * &packetSize,
+ * maxPacketSize
* );
*
* if( status == MQTTSuccess )
* {
- * // The application should allocate or use a static #MQTTFixedBuffer_t
- * // of size >= packetSize to serialize the publish.
+ * // The publish packet can now be sent to the broker.
* }
* @endcode
*/
/* @[declare_mqtt_getpublishpacketsize] */
MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize );
+ const MQTTPropBuilder_t * pPublishProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize );
/* @[declare_mqtt_getpublishpacketsize] */
/**
@@ -689,6 +1247,8 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
* as the size returned by #MQTT_GetPublishPacketSize.
*
* @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] pPublishProperties MQTT v5.0 properties for the PUBLISH packet. Can be NULL
+ * if no properties are needed.
* @param[in] packetId packet ID generated by #MQTT_GetPacketId.
* @param[in] remainingLength Remaining Length provided by #MQTT_GetPublishPacketSize.
* @param[out] pFixedBuffer Buffer for packet serialization.
@@ -703,6 +1263,7 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTPropBuilder_t publishProperties = { 0 };
* MQTTFixedBuffer_t fixedBuffer;
* uint8_t buffer[ BUFFER_SIZE ];
* size_t remainingLength = 0, packetSize = 0;
@@ -715,9 +1276,9 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
* // identifier must be used.
* packetId = 0;
*
- * // Assume publishInfo has been initialized. Get publish packet size.
+ * // Assume publishInfo and publishProperties have been initialized. Get publish packet size.
* status = MQTT_GetPublishPacketSize(
- * &publishInfo, &remainingLength, &packetSize
+ * &publishInfo, &publishProperties, &remainingLength, &packetSize
* );
* assert( status == MQTTSuccess );
* assert( packetSize <= BUFFER_SIZE );
@@ -725,6 +1286,7 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
* // Serialize the publish packet into the fixed buffer.
* status = MQTT_SerializePublish(
* &publishInfo,
+ * &publishProperties,
* packetId,
* remainingLength,
* &fixedBuffer
@@ -738,8 +1300,9 @@ MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
*/
/* @[declare_mqtt_serializepublish] */
MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
+ const MQTTPropBuilder_t * pPublishProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_serializepublish] */
@@ -756,10 +1319,12 @@ MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
*
* @return #MQTTSuccess if the serialization is successful. Otherwise, #MQTTBadParameter.
*/
+/* @[declare_mqtt_serializepublishheaderwithouttopic] */
MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
- size_t remainingLength,
+ uint32_t remainingLength,
uint8_t * pBuffer,
size_t * headerSize );
+/* @[declare_mqtt_serializepublishheaderwithouttopic] */
/**
* @brief Serialize an MQTT PUBLISH packet header in the given buffer.
@@ -777,6 +1342,8 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
* as the size returned by #MQTT_GetPublishPacketSize.
*
* @param[in] pPublishInfo MQTT PUBLISH packet parameters.
+ * @param[in] pPublishProperties MQTT v5.0 properties for the PUBLISH packet. Can be NULL
+ * if no properties are needed.
* @param[in] packetId packet ID generated by #MQTT_GetPacketId.
* @param[in] remainingLength Remaining Length provided by #MQTT_GetPublishPacketSize.
* @param[out] pFixedBuffer Buffer for packet serialization.
@@ -792,11 +1359,13 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTPropBuilder_t publishProperties ;
* MQTTFixedBuffer_t fixedBuffer;
* uint8_t buffer[ BUFFER_SIZE ];
* size_t remainingLength = 0, packetSize = 0, headerSize = 0;
* uint16_t packetId;
* int32_t bytesSent;
+ * uint32_t maxPacketSize = pContext->connectionProperties.serverMaxPacketSize;
*
* fixedBuffer.pBuffer = buffer;
* fixedBuffer.size = BUFFER_SIZE;
@@ -805,10 +1374,9 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
* // identifier must be used.
* packetId = 0;
*
- * // Assume publishInfo has been initialized. Get the publish packet size.
+ * // Assume publishInfo and publishProperties have been initialized. Get the publish packet size.
* status = MQTT_GetPublishPacketSize(
- * &publishInfo, &remainingLength, &packetSize
- * );
+ * &publishInfo, &publishProperties, &remainingLength, &packetSize, maxPacketSize );
* assert( status == MQTTSuccess );
* // The payload will not be serialized, so the the fixed buffer does not need to hold it.
* assert( ( packetSize - publishInfo.payloadLength ) <= BUFFER_SIZE );
@@ -816,6 +1384,7 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
* // Serialize the publish packet header into the fixed buffer.
* status = MQTT_SerializePublishHeader(
* &publishInfo,
+ * &publishProperties,
* packetId,
* remainingLength,
* &fixedBuffer,
@@ -836,8 +1405,9 @@ MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t *
*/
/* @[declare_mqtt_serializepublishheader] */
MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
+ const MQTTPropBuilder_t * pPublishProperties,
uint16_t packetId,
- size_t remainingLength,
+ uint32_t remainingLength,
const MQTTFixedBuffer_t * pFixedBuffer,
size_t * pHeaderSize );
/* @[declare_mqtt_serializepublishheader] */
@@ -850,6 +1420,11 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
* @param[in] packetType Byte of the corresponding packet fixed header per the
* MQTT spec.
* @param[in] packetId Packet ID of the publish.
+ * @param[in] pAckProperties Optional properties to be added to the ACK packet.
+ * @param[in] pReasonCode Optional reason code to be added to the ACK packet.
+ *
+ * @note If any properties are provided to the function to be added to the ack
+ * packet, then a reason code must be provided as well.
*
* @return #MQTTBadParameter, #MQTTNoMemory, or #MQTTSuccess.
*
@@ -874,8 +1449,8 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
* // The byte representing a packet of type ACK. This function accepts PUBACK, PUBREC, PUBREL, or PUBCOMP.
* packetType = MQTT_PACKET_TYPE_PUBACK;
*
- * // Serialize the publish acknowledgment into the fixed buffer.
- * status = MQTT_SerializeAck( &fixedBuffer, packetType, packetId );
+ * // Serialize the publish acknowledgment into the fixed buffer without any properties or reason code.
+ * status = MQTT_SerializeAck( &fixedBuffer, packetType, packetId, NULL, NULL );
*
* if( status == MQTTSuccess )
* {
@@ -886,43 +1461,69 @@ MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo
/* @[declare_mqtt_serializeack] */
MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
uint8_t packetType,
- uint16_t packetId );
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pAckProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode );
/* @[declare_mqtt_serializeack] */
/**
* @brief Get the size of an MQTT DISCONNECT packet.
*
+ * @param[in] pDisconnectProperties MQTT DISCONNECT properties builder. Pass NULL if
+ * not used.
+ * @param[out] pRemainingLength The Remaining Length of the MQTT DISCONNECT packet.
* @param[out] pPacketSize The size of the MQTT DISCONNECT packet.
+ * @param[in] maxPacketSize Maximum packet size allowed by the server.
+ * @param[in] pReasonCode The reason code for the disconnect. Pass NULL if not used -
+ * only valid if the properties are NULL too.
*
- * @return #MQTTSuccess, or #MQTTBadParameter if @p pPacketSize is NULL.
+ * @return #MQTTSuccess, or #MQTTBadParameter if parameters are invalid
*
* Example
* @code{c}
*
* // Variables used in this example.
* MQTTStatus_t status;
+ * size_t remainingLength = 0;
* size_t packetSize = 0;
+ * uint32_t maxPacketSize;
+ * MQTTPropBuilder_t disconnectProperties ;
+ * MQTTSuccessFailReasonCode_t reasonCode;
*
- * // Get the size requirement for the disconnect packet.
- * status = MQTT_GetDisconnectPacketSize( &packetSize );
- * assert( status == MQTTSuccess );
- * assert( packetSize == 2 );
+ * //Set property builder. The details are out of scope for this example.
+ * initializePropertyBuilder( &disconnectProperties );
*
- * // The application should allocate or use a static #MQTTFixedBuffer_t of
- * // size >= 2 to serialize the disconnect packet.
+ * //Set the parameters.
+ * // Get the size requirement for the disconnect packet.
+ * status = MQTT_GetDisconnectPacketSize( &disconnectProperties, &remainingLength,&packetSize,maxPacketSize, reasonCode );
*
+ * if( status == MQTTSuccess )
+ * {
+ * // Send the disconnect packet.
+ * }
* @endcode
*/
/* @[declare_mqtt_getdisconnectpacketsize] */
-MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize );
+MQTTStatus_t MQTT_GetDisconnectPacketSize( const MQTTPropBuilder_t * pDisconnectProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ MQTTSuccessFailReasonCode_t * pReasonCode );
/* @[declare_mqtt_getdisconnectpacketsize] */
/**
* @brief Serialize an MQTT DISCONNECT packet into the given buffer.
*
* The input #MQTTFixedBuffer_t.size must be at least as large as the size
- * returned by #MQTT_GetDisconnectPacketSize.
- *
+ * returned by #MQTT_GetDisconnectPacketSize. This function should only be called
+ * after #MQTT_GetDisconnectPacketSize to ensure proper buffer sizing.
+ *
+ * @param[in] pDisconnectProperties MQTT v5.0 properties for the DISCONNECT packet. Can be NULL
+ * if no properties are needed.
+ * @param[in] pReasonCode The reason code for the disconnect. For MQTT v5.0, this indicates
+ * why the connection is being terminated. If this is NULL, then the pDisconnectProperties must
+ * be NULL as well.
+ * @param[in] remainingLength Remaining Length provided by #MQTT_GetDisconnectPacketSize.
* @param[out] pFixedBuffer Buffer for packet serialization.
*
* @return #MQTTNoMemory if pFixedBuffer is too small to hold the MQTT packet;
@@ -935,18 +1536,26 @@ MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize );
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTFixedBuffer_t fixedBuffer;
+ * MQTTPropBuilder_t disconnectProperties = { 0 };
* uint8_t buffer[ BUFFER_SIZE ];
+ * size_t remainingLength = 0, packetSize = 0;
*
* fixedBuffer.pBuffer = buffer;
* fixedBuffer.size = BUFFER_SIZE;
*
* // Get the disconnect packet size.
- * status = MQTT_GetDisconnectPacketSize( &packetSize );
+ * status = MQTT_GetDisconnectPacketSize( &disconnectProperties,
+ * MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION,
+ * &remainingLength,
+ * &packetSize );
* assert( status == MQTTSuccess );
* assert( packetSize <= BUFFER_SIZE );
*
* // Serialize the disconnect into the fixed buffer.
- * status = MQTT_SerializeDisconnect( &fixedBuffer );
+ * status = MQTT_SerializeDisconnect( &disconnectProperties,
+ * MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION,
+ * remainingLength,
+ * &fixedBuffer );
*
* if( status == MQTTSuccess )
* {
@@ -955,7 +1564,10 @@ MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize );
* @endcode
*/
/* @[declare_mqtt_serializedisconnect] */
-MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer );
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTPropBuilder_t * pDisconnectProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_serializedisconnect] */
/**
@@ -983,7 +1595,7 @@ MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer );
* @endcode
*/
/* @[declare_mqtt_getpingreqpacketsize] */
-MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize );
+MQTTStatus_t MQTT_GetPingreqPacketSize( uint32_t * pPacketSize );
/* @[declare_mqtt_getpingreqpacketsize] */
/**
@@ -1033,8 +1645,14 @@ MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer );
* @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
* @param[out] pPacketId The packet ID obtained from the buffer.
* @param[out] pPublishInfo Struct containing information about the publish.
+ * @param[in] propBuffer Buffer to hold the properties.
+ * @param[in] maxPacketSize Maximum packet size.
+ * @param[in] topicAliasMax Maximum topic alias specified in the CONNECT packet.
*
- * @return #MQTTBadParameter, #MQTTBadResponse, or #MQTTSuccess.
+ * @return
+ * - #MQTTBadParameter if invalid parameters are passed
+ * - #MQTTBadResponse if invalid packet is read
+ * - #MQTTSuccess otherwise.
*
* Example
* @code{c}
@@ -1052,7 +1670,10 @@ MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer );
* MQTTStatus_t status;
* MQTTPacketInfo_t incomingPacket;
* MQTTPublishInfo_t publishInfo = { 0 };
+ * MQTTPropBuilder_t propBuffer ;
* uint16_t packetId;
+ * uint32_t maxPacketSize = pContext->connectionProperties.maxPacketSize;
+ * uint16_t topicAliasMax = pContext->connectionProperties.topicAliasMax;
*
* int32_t bytesRecvd;
* // A buffer to hold remaining data of the incoming packet.
@@ -1076,7 +1697,8 @@ MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer );
* // Deserialize the publish information if the incoming packet is a publish.
* if( ( incomingPacket.type & 0xF0 ) == MQTT_PACKET_TYPE_PUBLISH )
* {
- * status = MQTT_DeserializePublish( &incomingPacket, &packetId, &publishInfo );
+ * status = MQTT_DeserializePublish( &incomingPacket, &packetId, &publishInfo,
+ * &propBuffer, maxPacketSize, topicAliasMax );
* if( status == MQTTSuccess )
* {
* // The deserialized publish information can now be used from `publishInfo`.
@@ -1087,19 +1709,28 @@ MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer );
/* @[declare_mqtt_deserializepublish] */
MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- MQTTPublishInfo_t * pPublishInfo );
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * propBuffer,
+ uint32_t maxPacketSize,
+ uint16_t topicAliasMax );
/* @[declare_mqtt_deserializepublish] */
/**
- * @brief Deserialize an MQTT CONNACK, SUBACK, UNSUBACK, PUBACK, PUBREC, PUBREL,
- * PUBCOMP, or PINGRESP.
+ * @brief Deserialize an MQTT PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, or PINGRESP.
*
* @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
- * @param[out] pPacketId The packet ID of obtained from the buffer. Not used
- * in CONNACK or PINGRESP.
- * @param[out] pSessionPresent Boolean flag from a CONNACK indicating present session.
- *
- * @return #MQTTBadParameter, #MQTTBadResponse, #MQTTServerRefused, or #MQTTSuccess.
+ * @param[out] pPacketId The packet ID obtained from the buffer.
+ * @param[out] pReasonCode Struct to store reason code(s) from the acknowledgment packet.
+ * Contains the success/failure status of the corresponding request.
+ * @param[out] pPropBuffer Struct to store the deserialized acknowledgment properties.
+ * Will contain any MQTT v5.0 properties included in the ack packet.
+ * @param[in,out] pConnectProperties Struct to store the deserialized connect/connack properties.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the packet was successfully deserialized
+ * - #MQTTBadParameter if invalid parameters are passed
+ * - #MQTTServerRefused if the server explicitly rejected the request, either in the CONNACK or a SUBACK.
+ * - #MQTTBadResponse if the packet type is invalid or packet parsing fails
*
* Example
* @code{c}
@@ -1107,33 +1738,54 @@ MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
* // Variables used in this example.
* MQTTStatus_t status;
* MQTTPacketInfo_t incomingPacket;
- * // Used for SUBACK, UNSUBACK, PUBACK, PUBREC, PUBREL, and PUBCOMP.
* uint16_t packetId;
- * // Used for CONNACK.
- * bool sessionPresent;
+ * MQTTReasonCodeInfo_t reasonCode ; // Can be set to NULL if the incoming packet is CONNACK or PINGRESP
+ * MQTTPropBuilder_t propBuffer; // Can be set to NULL if the user does not want any incoming properties.
+ * MQTTConnectionProperties_t connectionProperties = pContext->connectionProperties; // Cannot be set to NULL.
*
* // Receive an incoming packet and populate all fields. The details are out of scope
* // for this example.
- * receiveIncomingPacket( &incomingPacket );
- *
- * // Deserialize ack information if the incoming packet is not a publish.
- * if( ( incomingPacket.type & 0xF0 ) != MQTT_PACKET_TYPE_PUBLISH )
+ * receiveIncomingPacket(&incomingPacket);
+ *
+ * // Deserialize ack information if the incoming packet is a publish ack.
+ * status = MQTT_DeserializeAck( &incomingPacket,
+ * &packetId,
+ * &reasonCode,
+ * &propBuffer,
+ * &connectionProperties );
+ * if(status == MQTTSuccess)
* {
- * status = MQTT_DeserializeAck( &incomingPacket, &packetId, &sessionPresent );
- * if( status == MQTTSuccess )
- * {
- * // The packet ID or session present flag information is available. For
- * // ping response packets, the only information is the status code.
- * }
+ * // Ack information is now available.
* }
* @endcode
*/
/* @[declare_mqtt_deserializeack] */
MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- bool * pSessionPresent );
+ MQTTReasonCodeInfo_t * pReasonCode,
+ MQTTPropBuilder_t * pPropBuffer,
+ MQTTConnectionProperties_t * pConnectProperties );
/* @[declare_mqtt_deserializeack] */
+/**
+ * @brief Deserialize an MQTT CONNACK.
+ *
+ * @param[in] pIncomingPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[out] pSessionPresent Boolean flag from a CONNACK indicating present session.
+ * @param[out] pPropBuffer Struct to store the deserialized acknowledgment properties.
+ * Will contain any MQTT v5.0 properties included in the ack packet.
+ * @param[in,out] pConnectProperties Struct to store the deserialized connect/connack properties.
+ * This parameter cannot be NULL.
+ *
+ * @return #MQTTBadParameter, #MQTTBadResponse, #MQTTServerRefused, or #MQTTSuccess.
+ */
+/* @[declare_mqtt_deserializeconnack] */
+MQTTStatus_t MQTT_DeserializeConnAck( const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropBuffer,
+ MQTTConnectionProperties_t * pConnectProperties );
+/* @[declare_mqtt_deserializeconnack] */
+
/**
* @brief Extract the MQTT packet type and length from incoming packet.
*
@@ -1234,76 +1886,1246 @@ MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
* #MQTTBadParameter for invalid parameters
*/
/* @[declare_mqtt_updateduplicatepublishflag] */
-MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader , bool set);
+MQTTStatus_t MQTT_UpdateDuplicatePublishFlag( uint8_t * pHeader, bool set );
/* @[declare_mqtt_updateduplicatepublishflag] */
/**
- * @fn uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex, const MQTTConnectInfo_t * pConnectInfo, const MQTTPublishInfo_t * pWillInfo, size_t remainingLength );
- * @brief Serialize the fixed part of the connect packet header.
+ * @brief Initialize an MQTTConnectionProperties_t.
+ *
+ * @note This function initializes the connect properties to default values.
+ * This function should only be used if using only serializer functions
+ * throughout the connection. It is also important to only call this function
+ * before sending the connect packet.
*
- * @param[out] pIndex Pointer to the buffer where the header is to
- * be serialized.
- * @param[in] pConnectInfo The connect information.
- * @param[in] pWillInfo The last will and testament information.
- * @param[in] remainingLength The remaining length of the packet to be
- * serialized.
+ * @param[in] pConnectProperties The connect properties to initialize.
*
- * @return A pointer to the end of the encoded string.
+ * @return
+ * - #MQTTBadParameter if pConnectProperties is NULL.
+ * - #MQTTSuccess otherwise.
*/
+/* @[declare_mqtt_initconnect] */
+MQTTStatus_t MQTT_InitConnect( MQTTConnectionProperties_t * pConnectProperties );
+/* @[declare_mqtt_initconnect] */
/**
- * @cond DOXYGEN_IGNORE
- * Doxygen should ignore this definition, this function is private.
+ * @brief Initialize the property builder.
+ *
+ * @param[out] pPropertyBuilder Property builder to initialize.
+ * @param[in] buffer Buffer to store the properties.
+ * @param[in] length Length of the buffer.
+ *
+ * @return
+ * - #MQTTBadParameter if invalid parameters are passed.
+ * - #MQTTSuccess otherwise.
*/
-uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex,
- const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength );
-/** @endcond */
+/* @[declare_mqttpropertybuilder_init] */
+MQTTStatus_t MQTTPropertyBuilder_Init( MQTTPropBuilder_t * pPropertyBuilder,
+ uint8_t * buffer,
+ size_t length );
+/* @[declare_mqttpropertybuilder_init] */
/**
- * @fn uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength, uint8_t * pIndex, uint16_t packetId );
- * @brief Serialize the fixed part of the subscribe packet header.
+ * @brief Validates the properties specified for WILL Properties in the MQTT CONNECT packet.
*
- * @param[in] remainingLength The remaining length of the packet to be
- * serialized.
- * @param[in] pIndex Pointer to the buffer where the header is to
- * be serialized.
- * @param[in] packetId The packet ID to be serialized.
+ * @param[in] pPropertyBuilder Pointer to the property builder structure containing will properties.
*
- * @return A pointer to the end of the encoded string.
+ * @return Returns one of the following:
+ * - #MQTTSuccess , #MQTTBadParameter or #MQTTBadResponse.
*/
+/* @[declare_mqtt_validatewillproperties] */
+MQTTStatus_t MQTT_ValidateWillProperties( const MQTTPropBuilder_t * pPropertyBuilder );
+/* @[declare_mqtt_validatewillproperties] */
-/**
- * @cond DOXYGEN_IGNORE
- * Doxygen should ignore this definition, this function is private.
+
+ /**
+ * @brief Validate the properties in a CONNECT packet.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder structure containing connect packet
+ * properties.
+ * @param[out] isRequestProblemInfoSet Whether the request problem info field is set in the properties.
+ * @param[out] pPacketSizeMaxValue Optional pointer to get the Maximum Packet Size from the properties.
+ * If not required, NULL can be passed.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess , #MQTTBadParameter or #MQTTBadResponse.
*/
-uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId );
-/** @endcond */
+/* @[declare_mqtt_validateconnectproperties] */
+MQTTStatus_t MQTT_ValidateConnectProperties( const MQTTPropBuilder_t * pPropertyBuilder,
+ bool * isRequestProblemInfoSet,
+ uint32_t * pPacketSizeMaxValue );
+/* @[declare_mqtt_validateconnectproperties] */
/**
- * @fn uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength, uint8_t * pIndex, uint16_t packetId );
- * @brief Serialize the fixed part of the unsubscribe packet header.
+ * @brief Adds a Subscription Identifier property to the MQTT property builder.
+ *
+ * This function adds a Subscription Identifier property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure where
+ * the Subscription Identifier will be added.
+ * Must not be NULL.
+ * @param[in] subscriptionId The Subscription Identifier value to be added.
+ * Must be greater than 0.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Subscription Identifier was successfully added
+ * - #MQTTBadParameter if pPropertyBuilder is NULL or subscriptionId is 0
+ * - #MQTTNoMemory if the property builder has insufficient space
+ *
+ * Example
+ * @code{c}
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPropBuilder_t propertyBuilder ; // Assume this is initialized properly
+ * size_t subscriptionId = 12345;
*
- * @param[in] remainingLength The remaining length of the packet to be
- * serialized.
- * @param[in] pIndex Pointer to the buffer where the header is to
- * be serialized.
- * @param[in] packetId The packet ID to be serialized.
+ * // Add Subscription Identifier to property builder
+ * status = MQTTPropAdd_SubscriptionId(&propertyBuilder, subscriptionId);
+ *
+ * if(status == MQTTSuccess)
+ * {
+ * // Subscription Identifier successfully added
+ * }
+ * @endcode
*
- * @return A pointer to the end of the encoded string.
+ * @note This property is only valid for MQTT v5.0 and above.
+ * @note The Subscription Identifier can be used in SUBSCRIBE packets and
+ * will be returned in matched PUBLISH packets.
*/
+/* @[declare_mqttpropadd_subscriptionid] */
+MQTTStatus_t MQTTPropAdd_SubscriptionId( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t subscriptionId,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_subscriptionid] */
+
/**
- * @cond DOXYGEN_IGNORE
- * Doxygen should ignore this definition, this function is private.
+ * @brief Adds User Property to the MQTT property builder.
+ *
+ * This function adds User Property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] userProperty The User Property to be added.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Subscription Identifier was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_userprop] */
+MQTTStatus_t MQTTPropAdd_UserProp( MQTTPropBuilder_t * pPropertyBuilder,
+ const MQTTUserProperty_t * userProperty,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_userprop] */
+
+/**
+ * @brief Adds Session Expiry Interval property to the MQTT property builder.
+ *
+ * This function adds Session Expiry Interval property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] sessionExpiry The Session Expiry Interval in seconds.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for validation.
+ * Can be NULL to skip packet type validation.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Session Expiry Interval was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_sessionexpiry] */
+MQTTStatus_t MQTTPropAdd_SessionExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t sessionExpiry,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_sessionexpiry] */
+
+/**
+ * @brief Adds Receive Maximum property to the MQTT property builder.
+ *
+ * This function adds Receive Maximum property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] receiveMax The maximum number of QoS 1 and QoS 2 messages allowed to be
+ * received simultaneously.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Receive Maximum was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_receivemax] */
+MQTTStatus_t MQTTPropAdd_ReceiveMax( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t receiveMax,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_receivemax] */
+
+/**
+ * @brief Adds Maximum Packet Size property to the MQTT property builder.
+ *
+ * This function adds Maximum Packet Size property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] maxPacketSize The maximum packet size the client is willing to accept.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Maximum Packet Size was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_maxpacketsize] */
+MQTTStatus_t MQTTPropAdd_MaxPacketSize( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t maxPacketSize,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_maxpacketsize] */
+
+/**
+ * @brief Adds Topic Alias Maximum property to the MQTT property builder.
+ *
+ * This function adds Topic Alias Maximum property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] topicAliasMax The maximum value of topic alias accepted by the client.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Topic Alias Maximum was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_topicaliasmax] */
+MQTTStatus_t MQTTPropAdd_TopicAliasMax( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t topicAliasMax,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_topicaliasmax] */
+
+/**
+ * @brief Adds Request Response Information property to the MQTT property builder.
+ *
+ * This function adds Request Response Information property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] requestResponseInfo Boolean indicating whether response information is requested.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Request Response Information was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_requestrespinfo] */
+MQTTStatus_t MQTTPropAdd_RequestRespInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ bool requestResponseInfo,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_requestrespinfo] */
+
+/**
+ * @brief Adds Request Problem Information property to the MQTT property builder.
+ *
+ * This function adds Request Problem Information property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] requestProblemInfo Boolean indicating whether problem information is requested.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Request Problem Information was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_requestprobinfo] */
+MQTTStatus_t MQTTPropAdd_RequestProbInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ bool requestProblemInfo,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_requestprobinfo] */
+
+/**
+ * @brief Adds Authentication Method property to the MQTT property builder.
+ *
+ * This function adds Authentication Method property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] authMethod Pointer to the authentication method string.
+ * @param[in] authMethodLength Length of the authentication method string (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Authentication Method was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_authmethod] */
+MQTTStatus_t MQTTPropAdd_AuthMethod( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * authMethod,
+ size_t authMethodLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_authmethod] */
+
+/**
+ * @brief Adds Authentication Data property to the MQTT property builder.
+ *
+ * This function adds Authentication Data property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] authData Pointer to the authentication data.
+ * @param[in] authDataLength Length of the authentication data (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Authentication Data was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_authdata] */
+MQTTStatus_t MQTTPropAdd_AuthData( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * authData,
+ size_t authDataLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_authdata] */
+
+/**
+ * @brief Adds Payload Format Indicator property to the MQTT property builder.
+ *
+ * This function adds Payload Format Indicator property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] payloadFormat Boolean indicating the payload format (true for UTF-8, false for unspecified bytes).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Payload Format Indicator was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_payloadformat] */
+MQTTStatus_t MQTTPropAdd_PayloadFormat( MQTTPropBuilder_t * pPropertyBuilder,
+ bool payloadFormat,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_payloadformat] */
+
+/**
+ * @brief Adds Message Expiry Interval property to the MQTT property builder.
+ *
+ * This function adds Message Expiry Interval property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] messageExpiry The message expiry interval in seconds.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Message Expiry Interval was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_messageexpiry] */
+MQTTStatus_t MQTTPropAdd_MessageExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t messageExpiry,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_messageexpiry] */
+
+/**
+ * @brief Adds Will Delay Interval property to the MQTT property builder.
+ *
+ * This function adds Message Expiry Interval property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] willDelayInterval Will Delay Interval in seconds.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Message Expiry Interval was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_willdelayinterval] */
+MQTTStatus_t MQTTPropAdd_WillDelayInterval( MQTTPropBuilder_t * pPropertyBuilder,
+ uint32_t willDelayInterval,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_willdelayinterval] */
+
+/**
+ * @brief Adds Topic Alias property to the MQTT property builder.
+ *
+ * This function adds Topic Alias property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] topicAlias The topic alias value.
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Topic Alias was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_topicalias] */
+MQTTStatus_t MQTTPropAdd_TopicAlias( MQTTPropBuilder_t * pPropertyBuilder,
+ uint16_t topicAlias,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_topicalias] */
+
+/**
+ * @brief Adds Response Topic property to the MQTT property builder.
+ *
+ * This function adds Response Topic property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] responseTopic Pointer to the response topic string.
+ * @param[in] responseTopicLength Length of the response topic string (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Response Topic was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_responsetopic] */
+MQTTStatus_t MQTTPropAdd_ResponseTopic( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * responseTopic,
+ size_t responseTopicLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_responsetopic] */
+/**
+ * @brief Adds Correlation Data property to the MQTT property builder.
+ *
+ * This function adds Correlation Data property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] pCorrelationData Pointer to the correlation data.
+ * @param[in] correlationLength Length of the correlation data (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Correlation Data was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_correlationdata] */
+MQTTStatus_t MQTTPropAdd_CorrelationData( MQTTPropBuilder_t * pPropertyBuilder,
+ const void * pCorrelationData,
+ size_t correlationLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_correlationdata] */
+
+/**
+ * @brief Adds Content Type property to the MQTT property builder.
+ *
+ * This function adds Content Type property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] contentType Pointer to the content type string.
+ * @param[in] contentTypeLength Length of the content type string (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Content Type was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_contenttype] */
+MQTTStatus_t MQTTPropAdd_ContentType( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * contentType,
+ size_t contentTypeLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_contenttype] */
+
+/**
+ * @brief Adds Reason String property to the MQTT property builder.
+ *
+ * This function adds Reason String property to the property builder.
+ *
+ * @param[out] pPropertyBuilder Pointer to the property builder structure.
+ * @param[in] pReasonString Pointer to the reason string.
+ * @param[in] reasonStringLength Length of the reason string (must be less than 65536).
+ * @param[in] pOptionalMqttPacketType Optional MQTT packet type for which the property
+ * is being added. The function will check whether the given property can be
+ * added to the packet type if it is provided.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the Reason String was successfully added
+ * - #MQTTBadParameter if an invalid parameter is passed
+ * - #MQTTNoMemory if the property builder has insufficient space
+ */
+/* @[declare_mqttpropadd_reasonstring] */
+MQTTStatus_t MQTTPropAdd_ReasonString( MQTTPropBuilder_t * pPropertyBuilder,
+ const char * pReasonString,
+ size_t reasonStringLength,
+ const uint8_t * pOptionalMqttPacketType );
+/* @[declare_mqttpropadd_reasonstring] */
+
+/**
+ * @brief Validates the properties of a SUBSCRIBE packet.
+ *
+ * This function validates the properties in the property builder for a SUBSCRIBE packet.
+ *
+ * @param[in] isSubscriptionIdAvailable Boolean indicating if subscription identifiers are supported.
+ * @param[in] propBuilder Pointer to the property builder structure.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the properties are valid
+ * - #MQTTBadParameter if an invalid parameter is passed
+ */
+/* @[declare_mqtt_validatesubscribeproperties] */
+MQTTStatus_t MQTT_ValidateSubscribeProperties( bool isSubscriptionIdAvailable,
+ const MQTTPropBuilder_t * propBuilder );
+/* @[declare_mqtt_validatesubscribeproperties] */
+
+/**
+ * @brief Updates the MQTT context with connect properties from the property builder.
+ *
+ * This function processes the property builder and updates the connect properties
+ * in the MQTT context. It handles the conversion and validation of properties from
+ * the property builder to the connect properties structure.
+ *
+ * @param[in] pPropBuilder Pointer to the property builder containing MQTT properties.
+ * Must not be NULL.
+ * @param[out] pConnectProperties Pointer to the connection properties structure to be updated.
+ * Must not be NULL.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if properties were successfully updated
+ * - #MQTTBadParameter, MQTTBadResponse if invalid parameters are passed
+ *
+ * Example
+ * @code{c}
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPropBuilder_t propBuilder = { 0 };
+ * MQTTConnectionProperties_t connectionProperties = { 0 };
+ *
+ * // Initialize property builder with desired properties
+ * // ...
+ *
+ * // Update connect properties
+ * status = updateContextWithConnectProps( &propBuilder, &connectionProperties );
+ *
+ * if(status == MQTTSuccess)
+ * {
+ * // Properties successfully updated in the context
+ * }
+ * @endcode
+ */
+
+MQTTStatus_t updateContextWithConnectProps( const MQTTPropBuilder_t * pPropBuilder,
+ MQTTConnectionProperties_t * pConnectProperties );
+
+/**
+ * @brief Get the property type at the current index in the property builder.
+ *
+ * This function retrieves the property identifier byte at the specified index
+ * and validates that it is a recognized MQTT v5 property type. The index is
+ * not advanced by this function - use the appropriate MQTTPropGet_* function
+ * to retrieve the property value and advance the index.
+ *
+ * @param[in] mqttPropBuilder Property builder containing the properties.
+ * @param[in] index Current index in the property builder buffer.
+ * @param[out] property Pointer to store the property type identifier.
+ *
+ * @return #MQTTSuccess if property type is retrieved and valid;
+ * #MQTTBadParameter if invalid parameters are passed, index is out of bounds,
+ * or the property type is not recognized.
+ */
+MQTTStatus_t MQTT_GetNextPropertyType( MQTTPropBuilder_t * mqttPropBuilder,
+ size_t * index,
+ uint8_t * property );
+
+/**
+ * @brief Skip the next property in the property builder without extracting its value.
+ *
+ * This function advances the current index past the property at the current position
+ * in the property buffer. It validates the property ID and ensures the property data
+ * is within bounds, but does not extract or return the property value. This is useful
+ * for iterating through properties when only specific properties need to be extracted.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * On success, updated to point to the next property.
+ *
+ * @return #MQTTSuccess if the property is successfully skipped;
+ * #MQTTBadParameter if parameters are invalid, property ID is unknown, or
+ * the property data extends beyond the buffer bounds;
+ * #MQTTEndOfProperties if currentIndex is already at or past the end of properties.
+ *
+ * Example
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPropBuilder_t propertyBuilder = { 0 };
+ * uint32_t currentIndex = 0;
+ * uint8_t propertyType;
+ *
+ * // Initialize property builder with received properties
+ * // (initialization details out of scope for this example)
+ * initializePropertyBuilder( &propertyBuilder );
+ *
+ * // Iterate through all properties
+ * while( currentIndex < propertyBuilder.currentIndex )
+ * {
+ * // Get the property type at current position
+ * status = MQTT_GetNextPropertyType( &propertyBuilder, ¤tIndex, &propertyType );
+ *
+ * if( status != MQTTSuccess )
+ * {
+ * break;
+ * }
+ *
+ * // Only extract user properties, skip all others
+ * if( propertyType == MQTT_USER_PROPERTY_ID )
+ * {
+ * MQTTUserProperty_t userProp;
+ * status = MQTTPropGet_UserProp( &propertyBuilder, ¤tIndex, &userProp );
+ * // Process user property...
+ * }
+ * else
+ * {
+ * // Skip this property
+ * status = MQTT_SkipNextProperty( &propertyBuilder, ¤tIndex );
+ * }
+ *
+ * if( status != MQTTSuccess )
+ * {
+ * break;
+ * }
+ * }
+ * @endcode
+ */
+MQTTStatus_t MQTT_SkipNextProperty( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex );
+
+/**
+ * @brief Get User Property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pUserProperty Pointer to store the user property key-value pair.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_userprop] */
+MQTTStatus_t MQTTPropGet_UserProp( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ MQTTUserProperty_t * pUserProperty );
+/* @[declare_mqttpropget_userprop] */
+
+/**
+ * @brief Get Session Expiry Interval property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pSessionExpiry Pointer to store the session expiry interval in seconds.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_sessionexpiry] */
+MQTTStatus_t MQTTPropGet_SessionExpiry( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pSessionExpiry );
+/* @[declare_mqttpropget_sessionexpiry] */
+
+/**
+ * @brief Get Receive Maximum property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pReceiveMax Pointer to store the receive maximum value.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_receivemax] */
+MQTTStatus_t MQTTPropGet_ReceiveMax( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pReceiveMax );
+/* @[declare_mqttpropget_receivemax] */
+
+/**
+ * @brief Get Maximum QoS property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pMaxQos Pointer to store the maximum QoS level (0, 1, or 2).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_maxqos] */
+MQTTStatus_t MQTTPropGet_MaxQos( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pMaxQos );
+/* @[declare_mqttpropget_maxqos] */
+
+/**
+ * @brief Get Retain Available property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pRetainAvailable Pointer to store the retain available flag (0 or 1).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_retainavailable] */
+MQTTStatus_t MQTTPropGet_RetainAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pRetainAvailable );
+/* @[declare_mqttpropget_retainavailable] */
+
+/**
+ * @brief Get Maximum Packet Size property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pMaxPacketSize Pointer to store the maximum packet size in bytes.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_maxpacketsize] */
+MQTTStatus_t MQTTPropGet_MaxPacketSize( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pMaxPacketSize );
+/* @[declare_mqttpropget_maxpacketsize] */
+
+/**
+ * @brief Get Assigned Client Identifier property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pClientId Pointer to store the assigned client identifier string.
+ * @param[out] pClientIdLength Pointer to store the client identifier length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_assignedclientid] */
+MQTTStatus_t MQTTPropGet_AssignedClientId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pClientId,
+ size_t * pClientIdLength );
+/* @[declare_mqttpropget_assignedclientid] */
+
+/**
+ * @brief Get Topic Alias Maximum property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pTopicAliasMax Pointer to store the topic alias maximum value.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_topicaliasmax] */
+MQTTStatus_t MQTTPropGet_TopicAliasMax( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pTopicAliasMax );
+/* @[declare_mqttpropget_topicaliasmax] */
+
+/**
+ * @brief Get Reason String property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pReasonString Pointer to store the reason string.
+ * @param[out] pReasonStringLength Pointer to store the reason string length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_reasonstring] */
+MQTTStatus_t MQTTPropGet_ReasonString( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pReasonString,
+ size_t * pReasonStringLength );
+/* @[declare_mqttpropget_reasonstring] */
+
+/**
+ * @brief Get Wildcard Subscription Available property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pWildcardAvailable Pointer to store the wildcard subscription available flag (0 or 1).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_wildcardid] */
+MQTTStatus_t MQTTPropGet_WildcardId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pWildcardAvailable );
+/* @[declare_mqttpropget_wildcardid] */
+
+/**
+ * @brief Get Subscription Identifier Available property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pSubsIdAvailable Pointer to store the subscription identifier available flag (0 or 1).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_subsidavailable] */
+MQTTStatus_t MQTTPropGet_SubsIdAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pSubsIdAvailable );
+/* @[declare_mqttpropget_subsidavailable] */
+
+/**
+ * @brief Get Shared Subscription Available property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pSharedSubAvailable Pointer to store the shared subscription available flag (0 or 1).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_sharedsubavailable] */
+MQTTStatus_t MQTTPropGet_SharedSubAvailable( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pSharedSubAvailable );
+/* @[declare_mqttpropget_sharedsubavailable] */
+
+/**
+ * @brief Get Server Keep Alive property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pServerKeepAlive Pointer to store the server keep alive interval in seconds.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_serverkeepalive] */
+MQTTStatus_t MQTTPropGet_ServerKeepAlive( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pServerKeepAlive );
+/* @[declare_mqttpropget_serverkeepalive] */
+
+/**
+ * @brief Get Response Information property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pResponseInfo Pointer to store the response information string.
+ * @param[out] pResponseInfoLength Pointer to store the response information length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_responseinfo] */
+MQTTStatus_t MQTTPropGet_ResponseInfo( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pResponseInfo,
+ size_t * pResponseInfoLength );
+/* @[declare_mqttpropget_responseinfo] */
+
+/**
+ * @brief Get Server Reference property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pServerRef Pointer to store the server reference string.
+ * @param[out] pServerRefLength Pointer to store the server reference length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_serverref] */
+MQTTStatus_t MQTTPropGet_ServerRef( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pServerRef,
+ size_t * pServerRefLength );
+/* @[declare_mqttpropget_serverref] */
+
+/**
+ * @brief Get Authentication Method property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pAuthMethod Pointer to store the authentication method string.
+ * @param[out] pAuthMethodLen Pointer to store the authentication method length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_authmethod] */
+MQTTStatus_t MQTTPropGet_AuthMethod( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pAuthMethod,
+ size_t * pAuthMethodLen );
+/* @[declare_mqttpropget_authmethod] */
+
+/**
+ * @brief Get Authentication Data property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pAuthData Pointer to store the authentication data.
+ * @param[out] pAuthDataLen Pointer to store the authentication data length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_authdata] */
+MQTTStatus_t MQTTPropGet_AuthData( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pAuthData,
+ size_t * pAuthDataLen );
+/* @[declare_mqttpropget_authdata] */
+
+/**
+ * @brief Get Payload Format Indicator property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pPayloadFormat Pointer to store the payload format indicator (0=unspecified, 1=UTF-8).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_payloadformatindicator] */
+MQTTStatus_t MQTTPropGet_PayloadFormatIndicator( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint8_t * pPayloadFormat );
+/* @[declare_mqttpropget_payloadformatindicator] */
+
+/**
+ * @brief Get Message Expiry Interval property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pMessageExpiry Pointer to store the message expiry interval in seconds.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_messageexpiryinterval] */
+MQTTStatus_t MQTTPropGet_MessageExpiryInterval( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pMessageExpiry );
+/* @[declare_mqttpropget_messageexpiryinterval] */
+
+/**
+ * @brief Get Topic Alias property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pTopicAlias Pointer to store the topic alias value.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_topicalias] */
+MQTTStatus_t MQTTPropGet_TopicAlias( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint16_t * pTopicAlias );
+/* @[declare_mqttpropget_topicalias] */
+
+/**
+ * @brief Get Response Topic property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pResponseTopic Pointer to store the response topic string.
+ * @param[out] pResponseTopicLength Pointer to store the response topic length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_responsetopic] */
+MQTTStatus_t MQTTPropGet_ResponseTopic( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pResponseTopic,
+ size_t * pResponseTopicLength );
+/* @[declare_mqttpropget_responsetopic] */
+
+/**
+ * @brief Get Correlation Data property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pCorrelationData Pointer to store the correlation data.
+ * @param[out] pCorrelationDataLength Pointer to store the correlation data length.
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_correlationdata] */
+MQTTStatus_t MQTTPropGet_CorrelationData( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pCorrelationData,
+ size_t * pCorrelationDataLength );
+/* @[declare_mqttpropget_correlationdata] */
+
+/**
+ * @brief Get Subscription Identifier property from property builder.
+ *
+ * @param[in] pPropertyBuilder Property builder to get property from.
+ * @param[in,out] currentIndex Current index in the property builder buffer. Updated to next property on success.
+ * @param[out] pSubscriptionId Pointer to store the subscription identifier (variable byte integer).
+ *
+ * @return #MQTTSuccess if property is retrieved successfully;
+ * #MQTTBadParameter if invalid parameters are passed.
+ */
+/* @[declare_mqttpropget_subscriptionid] */
+MQTTStatus_t MQTTPropGet_SubscriptionId( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ uint32_t * pSubscriptionId );
+/* @[declare_mqttpropget_subscriptionid] */
+
+/**
+ * @brief Get the Content Type property from the property builder.
+ *
+ * This function extracts the Content Type property value from the property builder
+ * at the specified index. The Content Type property describes the content of the
+ * Application Message.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder containing the properties.
+ * @param[in,out] currentIndex Pointer to the current index in the property buffer.
+ * Updated to point past the property on success.
+ * @param[out] pContentType Pointer to store the extracted Content Type string.
+ * @param[out] pContentTypeLength Pointer to store the length of the Content Type string.
+ *
+ * @return #MQTTSuccess if the property is successfully extracted;
+ * #MQTTBadParameter if parameters are invalid or property is not Content Type.
+ */
+/* @[declare_mqttpropget_contenttype] */
+MQTTStatus_t MQTTPropGet_ContentType( MQTTPropBuilder_t * pPropertyBuilder,
+ size_t * currentIndex,
+ const char ** pContentType,
+ size_t * pContentTypeLength );
+/* @[declare_mqttpropget_contenttype] */
+
+/**
+ * @brief Validates the properties of a PUBLISH packet.
+ *
+ * This function validates the properties in the property builder for a PUBLISH packet.
+ *
+ * @param[in] serverTopicAliasMax Maximum topic alias value allowed by the server.
+ * @param[in] propBuilder Pointer to the property builder structure.
+ * @param[out] topicAlias Pointer to store the topic alias value if present.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess if the properties are valid
+ * - #MQTTBadParameter if invalid parameters are passed
+ * - #MQTTBadResponse if an invalid packet is read
+ */
+/* @[declare_mqtt_validatepublishproperties] */
+MQTTStatus_t MQTT_ValidatePublishProperties( uint16_t serverTopicAliasMax,
+ const MQTTPropBuilder_t * propBuilder,
+ uint16_t * topicAlias );
+/* @[declare_mqtt_validatepublishproperties] */
+
+/**
+ * @brief Validate the publish parameters present in the given publish structure @p pPublishInfo.
+ *
+ * This function must be called before #MQTT_GetPublishPacketSize in order to validate the publish parameters.
+ *
+ * @param[in] pPublishInfo MQTT publish packet parameters.
+ * @param[in] retainAvailable Whether server allows retain or not.
+ * @param[in] maxQos Maximum QoS supported by the server.
+ * @param[in] topicAlias Topic alias in the PUBLISH packet.
+ * @param[in] maxPacketSize Maximum packet size allowed by the server.
+ *
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * Example
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPublishInfo_t publishInfo = {0};
+ * uint16_t topicAlias;
+ * uint8_t retainAvailable;
+ * uint8_t maxQos;
+ * // Set in the CONNACK packet.
+ * uint32_t maxPacketSize ;
+ *
+ * //Set the publish info parameters.
+ *
+ * //Validate the publish packet
+ * status = MQTT_ValidatePublishParams(&publishInfo, retainAvailable, maxQos, topicAlias, maxPacketSize);
+ *
+ * if( status == MQTTSuccess )
+ * {
+ * // Get the packet size and serialize the publish packet.
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_validatepublishparams] */
+MQTTStatus_t MQTT_ValidatePublishParams( const MQTTPublishInfo_t * pPublishInfo,
+ uint8_t retainAvailable,
+ uint8_t maxQos,
+ uint16_t topicAlias,
+ uint32_t maxPacketSize );
+/* @[declare_mqtt_validatepublishparams] */
+
+/**
+ * @brief Validates the properties specified for an MQTT PUBLISH ACK packet.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder structure containing unsubscribe properties.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess , #MQTTBadParameter or #MQTTBadResponse.
+ */
+/* @[declare_mqtt_validatepublishackproperties] */
+MQTTStatus_t MQTT_ValidatePublishAckProperties( const MQTTPropBuilder_t * pPropertyBuilder );
+/* @[declare_mqtt_validatepublishackproperties] */
+
+/**
+ * @brief Validates the properties specified for an MQTT UNSUBSCRIBE packet.
+ *
+ * @param[in] pPropertyBuilder Pointer to the property builder structure containing unsubscribe properties.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess , #MQTTBadParameter or #MQTTBadResponse.
+ */
+/* @[declare_mqtt_validateunsubscribeproperties] */
+MQTTStatus_t MQTT_ValidateUnsubscribeProperties( const MQTTPropBuilder_t * pPropertyBuilder );
+/* @[declare_mqtt_validateunsubscribeproperties] */
+
+/**
+ * @brief Get the size of an outgoing PUBLISH ACK packet.
+ *
+ * @note If no reason code is sent and property length is zero then #MQTT_SerializeAck can be used directly.
+ *
+ * @param[out] pRemainingLength The remaining length of the packet to be serialized.
+ * @param[out] pPacketSize The size of the packet to be serialized.
+ * @param[in] maxPacketSize Maximum packet size allowed by the server.
+ * @param[in] ackPropertyLength The length of the properties.
+ *
+ * @return #MQTTBadParameter if invalid parameters are passed;
+ * #MQTTSuccess otherwise.
+ *
+ * Example
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTFixedBuffer_t fixedBuffer;
+ * uint8_t buffer[ BUFFER_SIZE ];
+ * MQTTAckInfo_t ackInfo;
+ * uint16_t sessionExpiry;
+ *
+ * fixedBuffer.pBuffer = buffer;
+ * fixedBuffer.size = BUFFER_SIZE;
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * size_t remainingLength =0;
+ * size_t packetSize = 0;
+ * size_t ackPropertyLength = 0;
+ * uint32_t maxPacketSize;
+ * //set the parameters.
+ * // Get the size requirement for the ack packet.
+ * status = MQTT_GetAckPacketSize(&remainingLength,&packetSize,maxPacketSize, ackPropertyLength);
+ * }
+ * @endcode
+ */
+/* @[declare_mqtt_getackpacketsize] */
+MQTTStatus_t MQTT_GetAckPacketSize( uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ size_t ackPropertyLength );
+/* @[declare_mqtt_getackpacketsize] */
+
+/**
+ * @brief Validates the properties specified for an MQTT DISCONNECT packet.
+ *
+ * @param[in] connectSessionExpiry The session expiry interval that was specified
+ * in the CONNECT packet. Used to validate that the
+ * DISCONNECT session expiry is not non-zero while
+ * connectSessionExpiry is zero.
+ * @param[in] pPropertyBuilder Pointer to the property builder structure containing subscribe properties.
+ *
+ * @return Returns one of the following:
+ * - #MQTTSuccess , #MQTTBadParameter or #MQTTBadResponse.
+ */
+/* @[declare_mqtt_validatedisconnectproperties] */
+MQTTStatus_t MQTT_ValidateDisconnectProperties( uint32_t connectSessionExpiry,
+ const MQTTPropBuilder_t * pPropertyBuilder );
+/* @[declare_mqtt_validatedisconnectproperties] */
+
+/**
+ * @brief Deserialize an MQTT Disconnect packet.
+ *
+ * @param[in] pPacket #MQTTPacketInfo_t containing the buffer.
+ * @param[in] maxPacketSize Maximum packet size allowed by the client.
+ * @param[out] pDisconnectInfo Struct containing disconnect reason code
+ * @param[out] pPropBuffer MQTTPropBuilder_t to store the deserialized properties.
+ *
+ * @return #MQTTBadParameter, #MQTTBadResponse or #MQTTSuccess.
+ *
+ * Example
+ * @code{c}
+ *
+ * // Variables used in this example.
+ * MQTTStatus_t status;
+ * MQTTPacketInfo_t incomingPacket;
+ * MQTTReasonCodeInfo_t disconnectInfo;
+ * uint32_t maxPacketSize;
+ * MQTTPropBuilder_t propBuffer; // Assume this is initialized properly
+ * // Receive an incoming packet and populate all fields. The details are out of scope
+ * // for this example.
+ * receiveIncomingPacket( &incomingPacket );
+ *
+ * // Deserialize disconnect information.
+ * if( ( incomingPacket.type) == MQTT_PACKET_TYPE_DISCONNECT )
+ * {
+ * status = MQTT_DeserializeDisconnect(&incomingPacket,
+ * maxPacketSize,
+ * &disconnectInfo,
+ * &propBuffer);
+ * if( status == MQTTSuccess )
+ * {
+ * // Disconnect information is available.
+ * }
+ * }
+ * @endcode
*/
-uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId );
-/** @endcond */
+/* @[declare_mqtt_deserializedisconnect] */
+MQTTStatus_t MQTT_DeserializeDisconnect( const MQTTPacketInfo_t * pPacket,
+ uint32_t maxPacketSize,
+ MQTTReasonCodeInfo_t * pDisconnectInfo,
+ MQTTPropBuilder_t * pPropBuffer );
+/* @[declare_mqtt_deserializedisconnect] */
/* *INDENT-OFF* */
#ifdef __cplusplus
diff --git a/source/include/inttypes.readme b/source/include/inttypes.readme
new file mode 100644
index 000000000..418b00ea9
--- /dev/null
+++ b/source/include/inttypes.readme
@@ -0,0 +1,25 @@
+#if !defined(_INTTYPES_H_)
+#define _INTTYPES_H_
+
+
+/*******************************************************************************
+ * This file contains the definitions specified in inttypes.h. It is provided to
+ * allow the library to be built using compilers that do not provide their own
+ * inttypes.h defintion.
+ *
+ * To use this file:
+ *
+ * 1) Copy this file into a directory that is in your compiler's include path.
+ * The directory must be part of the include path for system header files,
+ * for example passed using gcc's "-I" or "-isystem" options.
+ *
+ * 2) Rename the copied file inttypes.h.
+ *
+ */
+
+/* This might cause some warnings. But this will lead to no loss of data. */
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+
+#endif
\ No newline at end of file
diff --git a/source/include/private/core_mqtt_serializer_private.h b/source/include/private/core_mqtt_serializer_private.h
new file mode 100644
index 000000000..4bdd4cb95
--- /dev/null
+++ b/source/include/private/core_mqtt_serializer_private.h
@@ -0,0 +1,723 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_serializer_private.h
+ * @brief Declares the private functions/macros to be used with serialization and
+ * deserialization by the core_mqtt library.
+ * DO NOT include this in your application.
+ *
+ * @note These functions should not be called by the application or relied upon
+ * since their implementation can change. These are for internal use by the
+ * library only.
+ */
+#ifndef CORE_MQTT_SERIALIZER_PRIVATE_H
+#define CORE_MQTT_SERIALIZER_PRIVATE_H
+
+#include
+
+#include "core_mqtt_serializer.h"
+
+/**
+ * @brief Position of the properties for the fieldSet.
+ *
+ * Each property that can be added to an MQTT packet is assigned a unique bit
+ * position (0–31). This macro defines the position of the property
+ * in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ *
+ * The `fieldSet` is used to track which properties have already been added to prevent
+ * duplication, as many MQTT v5 properties must not appear more than once in a packet.
+ */
+
+/**
+ * @brief Defines the position of the **Subscription Identifier**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SUBSCRIPTION_ID_POS ( 1 )
+
+/**
+ * @brief Defines the position of the **Session Expiry Interval**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SESSION_EXPIRY_INTERVAL_POS ( 2 )
+
+/**
+ * @brief Defines the position of the **Receive Maximum**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_RECEIVE_MAXIMUM_POS ( 3 )
+
+/**
+ * @brief Defines the position of the **Maximum Packet Size**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_MAX_PACKET_SIZE_POS ( 4 )
+
+/**
+ * @brief Defines the position of the **Topic Alias Maximum**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_TOPIC_ALIAS_MAX_POS ( 5 )
+
+/**
+ * @brief Defines the position of the **Request Response Information**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_REQUEST_RESPONSE_INFO_POS ( 6 )
+
+/**
+ * @brief Defines the position of the **Request Problem Information**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_REQUEST_PROBLEM_INFO_POS ( 7 )
+
+/**
+ * @brief Defines the position of the **Authentication Method**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_AUTHENTICATION_METHOD_POS ( 9 )
+
+/**
+ * @brief Defines the position of the **Authentication Data**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_AUTHENTICATION_DATA_POS ( 10 )
+
+/**
+ * @brief Defines the position of the **Payload Format Indicator**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_PAYLOAD_FORMAT_INDICATOR_POS ( 11 )
+
+/**
+ * @brief Defines the position of the **Message Expiry Interval**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_MESSAGE_EXPIRY_INTERVAL_POS ( 12 )
+
+/**
+ * @brief Defines the position of the **Topic Alias**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_TOPIC_ALIAS_POS ( 13 )
+
+/**
+ * @brief Defines the position of the **Response Topic**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_RESPONSE_TOPIC_POS ( 14 )
+
+/**
+ * @brief Defines the position of the **Correlation Data**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_CORRELATION_DATA_POS ( 15 )
+
+/**
+ * @brief Defines the position of the **Content Type**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_CONTENT_TYPE_POS ( 16 )
+
+/**
+ * @brief Defines the position of the **Reason String**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_REASON_STRING_POS ( 17 )
+
+/**
+ * @brief Defines the position of the **Will Delay Interval**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_WILL_DELAY_POS ( 18 )
+
+/**
+ * @brief Defines the position of the **Assigned Client Identifier**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_ASSIGNED_CLIENT_ID_POS ( 19 )
+
+/**
+ * @brief Defines the position of the **Server Keep Alive**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SERVER_KEEP_ALIVE_POS ( 20 )
+
+/**
+ * @brief Defines the position of the **Response Information**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_RESPONSE_INFORMATION_POS ( 21 )
+
+/**
+ * @brief Defines the position of the **Server Reference**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SERVER_REFERENCE_POS ( 22 )
+
+/**
+ * @brief Defines the position of the **Maximum QoS**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_MAX_QOS_POS ( 23 )
+
+/**
+ * @brief Defines the position of the **Retain Available**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_RETAIN_AVAILABLE_POS ( 24 )
+
+/**
+ * @brief Defines the position of the **Wildcard Subscription Available**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_WILDCARD_SUBSCRIPTION_AVAILABLE_POS ( 25 )
+
+/**
+ * @brief Defines the position of the **Subscription Identifier Available**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SUBSCRIPTION_ID_AVAILABLE_POS ( 26 )
+
+/**
+ * @brief Defines the position of the **Shared Subscription Available**
+ * property in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_SHARED_SUBSCRIPTION_AVAILABLE_POS ( 27 )
+
+/**
+ * @brief Defines the position of the **User property**
+ * in the `fieldSet` bitfield of the `MQTTPropBuilder_t` struct.
+ */
+#define MQTT_USER_PROP_POS ( 28 )
+
+/* MQTT CONNECT flags. */
+#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */
+#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */
+#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS 1. */
+#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS 2. */
+#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */
+#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */
+#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief User name present. */
+
+/**
+ * @brief Macro for decoding a 4-byte unsigned int from a sequence of bytes.
+ *
+ * @param[in] ptr A uint8_t* that points to the high byte.
+ */
+#define UINT32_DECODE( ptr ) \
+ ( uint32_t ) ( ( ( ( uint32_t ) ptr[ 0 ] ) << 24 ) | \
+ ( ( ( uint32_t ) ptr[ 1 ] ) << 16 ) | \
+ ( ( ( uint32_t ) ptr[ 2 ] ) << 8 ) | \
+ ( ( uint32_t ) ptr[ 3 ] ) )
+
+/**
+ * This macro serializes a 32-bit unsigned integer (`val`) into 4 bytes at the
+ * specified memory location (`addr`).
+ */
+#define WRITE_UINT32( addr, val ) \
+ { \
+ ( addr )[ 3 ] = ( uint8_t ) ( ( ( val ) >> 0 ) & 0xFFU ); \
+ ( addr )[ 2 ] = ( uint8_t ) ( ( ( val ) >> 8 ) & 0xFFU ); \
+ ( addr )[ 1 ] = ( uint8_t ) ( ( ( val ) >> 16 ) & 0xFFU ); \
+ ( addr )[ 0 ] = ( uint8_t ) ( ( ( val ) >> 24 ) & 0xFFU ); \
+ }
+
+/**
+ * @brief Set a bit in an 8-bit unsigned integer.
+ */
+#define UINT8_SET_BIT( x, position ) ( ( x ) = ( uint8_t ) ( ( x ) | ( 0x01U << ( position ) ) ) )
+
+/**
+ * @brief Clear a bit in an 8-bit unsigned integer.
+ */
+#define UINT8_CLEAR_BIT( x, position ) ( ( x ) = ( uint8_t ) ( ( x ) & ( ~( 0x01U << ( position ) ) ) ) )
+
+/**
+ * @brief Macro for checking if a bit is set in a 1-byte unsigned int.
+ *
+ * @param[in] x The unsigned int to check.
+ * @param[in] position Which bit to check.
+ */
+#define UINT8_CHECK_BIT( x, position ) ( ( ( x ) & ( 0x01U << ( position ) ) ) == ( 0x01U << ( position ) ) )
+
+/**
+ * @brief Get the high byte of a 16-bit unsigned integer.
+ */
+#define UINT16_HIGH_BYTE( x ) ( ( uint8_t ) ( ( x ) >> 8 ) )
+
+/**
+ * @brief Get the low byte of a 16-bit unsigned integer.
+ */
+#define UINT16_LOW_BYTE( x ) ( ( uint8_t ) ( ( x ) & 0x00ffU ) )
+
+/**
+ * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.
+ *
+ * @param[in] ptr A uint8_t* that points to the high byte.
+ */
+#define UINT16_DECODE( ptr ) \
+ ( uint16_t ) ( ( ( ( uint16_t ) ptr[ 0 ] ) << 8 ) | \
+ ( ( uint16_t ) ptr[ 1 ] ) )
+
+/**
+ * @brief Set a bit in an 32-bit unsigned integer.
+ */
+#define UINT32_SET_BIT( x, position ) \
+ ( ( x ) = ( uint32_t ) ( ( x ) | ( ( uint32_t ) 0x01U << ( position ) ) ) )
+
+/**
+ * @brief Macro for checking if a bit is set in a 4-byte unsigned int.
+ *
+ * @param[in] x The unsigned int to check.
+ * @param[in] position Which bit to check.
+ */
+#define UINT32_CHECK_BIT( x, position ) \
+ ( ( ( uint32_t ) ( x ) & ( ( uint32_t ) 0x01U << ( position ) ) ) == ( ( uint32_t ) 0x01U << ( position ) ) )
+
+/**
+ * @brief Per the MQTT spec, the largest "Remaining Length" of an MQTT
+ * packet is this value, 256 MB.
+ */
+#define MQTT_MAX_REMAINING_LENGTH ( 268435455UL )
+
+/**
+ * @brief A value that represents an invalid remaining length.
+ *
+ * This value is greater than what is allowed by the MQTT specification.
+ */
+#define MQTT_REMAINING_LENGTH_INVALID ( ( uint32_t ) MQTT_MAX_REMAINING_LENGTH + 1U )
+
+/**
+ * @brief Per the MQTT spec, the max packet size can be of max remaining length + 5 bytes.
+ * Fixed header
+ * MQTT packet type nibble + MQTT flags nibble 1
+ * Maximum bytes used to encode the remaining length 4
+ */
+#define MQTT_MAX_PACKET_SIZE ( MQTT_MAX_REMAINING_LENGTH + 5U )
+
+/**
+ * @brief A value that represents maximum value of UTF-8 encoded string.
+ */
+#define MQTT_MAX_UTF8_STR_LENGTH ( ( uint32_t ) 65535 )
+
+/**
+ * @brief A value that represents the maximum value which can fit in a
+ * variable byte integer.
+ */
+#define MAX_VARIABLE_LENGTH_INT_VALUE ( ( uint32_t ) 268435455U )
+
+/**
+ * @brief A macro to check whether the uint32_t values will overflow when converted
+ * to size_t.
+ *
+ * Evaluates to true when the value provided will overflow size_t variable. False otherwise.
+ */
+#if ( SIZE_MAX >= UINT32_MAX )
+ #define CHECK_U32T_OVERFLOWS_SIZE_T( x ) false
+#else
+ #define CHECK_U32T_OVERFLOWS_SIZE_T( x ) ( ( x ) > SIZE_MAX )
+#endif
+
+/**
+ * @brief A macro to check whether the size_t values will overflow when converted
+ * to uint16_t which is used to represent MQTT UTF8 strings.
+ *
+ * Evaluates to true when the value provided will overflow 16-bit variable. False otherwise.
+ */
+#if ( 65535U >= SIZE_MAX )
+ #define CHECK_SIZE_T_OVERFLOWS_16BIT( x ) false
+#else
+ #define CHECK_SIZE_T_OVERFLOWS_16BIT( x ) ( ( x ) > UINT16_MAX )
+#endif
+
+/**
+ * @brief A macro to check whether the size_t values will overflow when converted
+ * to uint32_t.
+ *
+ * Evaluates to true when the value provided will overflow 32-bit variable. False otherwise.
+ */
+#if ( UINT32_MAX >= SIZE_MAX )
+ #define CHECK_SIZE_T_OVERFLOWS_32BIT( x ) false
+#else
+ #define CHECK_SIZE_T_OVERFLOWS_32BIT( x ) ( ( x ) > UINT32_MAX )
+#endif
+
+/**
+ * @brief A macro to check whether the addition of two unsigned 32-bit numbers will overflow.
+ *
+ * Evaluates to true when the addition will overflow. False otherwise.
+ */
+#define ADDITION_WILL_OVERFLOW_U32( x, y ) \
+ ( ( x ) > ( UINT32_MAX - ( y ) ) )
+
+/**
+ * @brief A macro to check whether the addition of two unsigned size_t numbers will overflow.
+ *
+ * Evaluates to true when the addition will overflow. False otherwise.
+ */
+#define ADDITION_WILL_OVERFLOW_SIZE_T( x, y ) \
+ ( ( x ) > ( SIZE_MAX - ( y ) ) )
+
+/**
+ * @fn size_t variableLengthEncodedSize( uint32_t length );
+ *
+ * @brief Retrieve the size of the remaining length if it were to be encoded.
+ *
+ * @param[in] length The remaining length to be encoded.
+ *
+ * @return The size of the remaining length if it were to be encoded.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+size_t variableLengthEncodedSize( uint32_t length );
+/** @endcond */
+
+/**
+ * @fn uint8_t * encodeString( uint8_t * pDestination, const char * pSource, uint16_t sourceLength );
+ *
+ * @brief Encode a string whose size is at maximum 16 bits in length.
+ *
+ * @param[out] pDestination Destination buffer for the encoding.
+ * @param[in] pSource The source string to encode.
+ * @param[in] sourceLength The length of the source string to encode.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * encodeString( uint8_t * pDestination,
+ const char * pSource,
+ uint16_t sourceLength );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeUserProp( const char ** pPropertyKey, size_t * pPropertyKeyLen, const char ** pPropertyValue, size_t * pPropertyValueLen, uint32_t * pPropertyLength, uint8_t ** pIndex );
+ *
+ * @brief Validate the length and decode a user property.
+ *
+ * @param[out] pPropertyKey To store the decoded key.
+ * @param[out] pPropertyKeyLen To store the decoded key length.
+ * @param[out] pPropertyValue To store the decoded value.
+ * @param[out] pPropertyValueLen To store the decoded value length.
+ * @param[in, out] pPropertyLength Value of the remaining property length.
+ * @param[in, out] pIndex Pointer to the current index of the buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeUserProp( const char ** pPropertyKey,
+ size_t * pPropertyKeyLen,
+ const char ** pPropertyValue,
+ size_t * pPropertyValueLen,
+ uint32_t * pPropertyLength,
+ uint8_t ** pIndex );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeUint32t( uint32_t * pProperty, uint32_t * pPropertyLength, bool * pUsed, uint8_t ** pIndex );
+ *
+ * @brief Validate the length and decode a 4 byte value.
+ *
+ * @param[out] pProperty To store the decoded property.
+ * @param[in, out] pPropertyLength Value of the remaining property length.
+ * @param[in, out] pUsed Whether the property is decoded before.
+ * @param[in, out] pIndex Pointer to the current index of the buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeUint32t( uint32_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeUint16t( uint16_t * pProperty, uint32_t * pPropertyLength, bool * pUsed, uint8_t ** pIndex );
+ *
+ * @brief Validate the length and decode a 2 byte value.
+ *
+ * @param[out] pProperty To store the decoded property.
+ * @param[in, out] pPropertyLength Value of the remaining property length.
+ * @param[in, out] pUsed Whether the property is decoded before.
+ * @param[in, out] pIndex Pointer to the current index of the buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeUint16t( uint16_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeUint8t( uint8_t * pProperty, uint32_t * pPropertyLength, bool * pUsed, uint8_t ** pIndex );
+ *
+ * @brief Validate the length and decode a 1 byte value.
+ *
+ * @param[out] pProperty To store the decoded property.
+ * @param[in, out] pPropertyLength Value of the remaining property length.
+ * @param[in, out] pUsed Whether the property is decoded before.
+ * @param[in, out] pIndex Pointer to the current index of the buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeUint8t( uint8_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex );
+/** @endcond */
+
+/**
+ * @fn uint8_t * encodeVariableLength( uint8_t * pDestination, uint32_t length );
+ *
+ * @brief Encodes the remaining length of the packet using the variable length
+ * encoding scheme provided in the MQTT 5.0 specification.
+ *
+ * @param[out] pDestination The destination buffer to store the encoded remaining
+ * length.
+ * @param[in] length The remaining length to encode.
+ *
+ * @return The location of the byte following the encoded value.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * encodeVariableLength( uint8_t * pDestination,
+ uint32_t length );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeUtf8( const char ** pProperty, size_t * pLength, uint32_t * pPropertyLength, bool * pUsed, uint8_t ** pIndex );
+ *
+ * @brief Validate the length and decode a utf 8 string.
+ *
+ * @param[out] pProperty To store the decoded string.
+ * @param[out] pLength Size of the decoded utf-8 string.
+ * @param[in, out] pPropertyLength Value of the remaining property length.
+ * @param[in, out] pUsed Whether the property is decoded before.
+ * @param[in, out] pIndex Pointer to the current index of the buffer.
+ *
+ * @return #MQTTSuccess, #MQTTBadResponse
+ **/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeUtf8( const char ** pProperty,
+ size_t * pLength,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeVariableLength( const uint8_t * pBuffer, size_t bufferLength, uint32_t * pLength );
+ *
+ * @brief Decodes the variable length by reading a single byte at a time.
+ *
+ * Uses the algorithm provided in the spec.
+ *
+ * @param[in] pBuffer Pointer to the buffer.
+ * @param[in] bufferLength Length of the remaining buffer.
+ * @param[out] pLength Decoded variable length
+ *
+ * @return #MQTTSuccess if variable length and paramters are valid else #MQTTBadResponse.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeVariableLength( const uint8_t * pBuffer,
+ size_t bufferLength,
+ uint32_t * pLength );
+/** @endcond */
+
+/**
+ * @fn uint8_t * serializeAckFixed( uint8_t * pIndex, uint8_t packetType, uint16_t packetId, uint32_t remainingLength, MQTTSuccessFailReasonCode_t reasonCode );
+ *
+ * @brief Serialize the fixed size part of the ack packet header.
+ *
+ * @param[out] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] packetType Type of publish ack
+ * @param[in] packetId Packed identifier of the ack packet.
+ * @param[in] remainingLength Remaining length of the ack packet.
+ * @param[in] reasonCode Reason code for the ack packet.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * serializeAckFixed( uint8_t * pIndex,
+ uint8_t packetType,
+ uint16_t packetId,
+ uint32_t remainingLength,
+ MQTTSuccessFailReasonCode_t reasonCode );
+/** @endcond */
+
+/**
+ * @fn MQTTStatus_t decodeSubackPropertyLength( const uint8_t * pIndex, uint32_t remainingLength, uint32_t * subackPropertyLength );
+ *
+ * @brief Decodes the property length field in a SUBACK packet.
+ *
+ * @param[in] pIndex Pointer to the start of the properties in the SUBACK packet.
+ * @param[in] remainingLength The remaining length of the MQTT packet being parsed, without Packet ID.
+ * @param[out] subackPropertyLength The decoded property length including the size of its encoded representation.
+ *
+ * @return #MQTTSuccess if the property length is successfully decoded;
+ * #MQTTBadResponse if the decoded property length is greater than the remaining length.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+MQTTStatus_t decodeSubackPropertyLength( const uint8_t * pIndex,
+ uint32_t remainingLength,
+ uint32_t * subackPropertyLength );
+/** @endcond */
+
+/**
+ * @fn uint8_t * serializeDisconnectFixed( uint8_t * pIndex, MQTTSuccessFailReasonCode_t * pReasonCode, uint32_t remainingLength );
+ *
+ * @brief Serialize the fixed size part of the disconnect packet header.
+ *
+ * @param[out] pIndex Pointer to the buffer where the header is to be serialized.
+ * @param[in] pReasonCode Reason code for the disconnect packet.
+ * @param[in] remainingLength Remaining length of the disconnect packet.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * serializeDisconnectFixed( uint8_t * pIndex,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength );
+/** @endcond */
+
+/**
+ * @fn uint8_t * serializeConnectFixedHeader( uint8_t * pIndex, const MQTTConnectInfo_t * pConnectInfo, const MQTTPublishInfo_t * pWillInfo, uint32_t remainingLength );
+ * @brief Serialize the fixed part of the connect packet header.
+ *
+ * @param[out] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] pConnectInfo The connect information.
+ * @param[in] pWillInfo The last will and testament information.
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * serializeConnectFixedHeader( uint8_t * pIndex,
+ const MQTTConnectInfo_t * pConnectInfo,
+ const MQTTPublishInfo_t * pWillInfo,
+ uint32_t remainingLength );
+/** @endcond */
+
+/**
+ * @fn uint8_t * serializeSubscribeHeader( uint32_t remainingLength, uint8_t * pIndex, uint16_t packetId );
+ * @brief Serialize the fixed part of the subscribe packet header.
+ *
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ * @param[in] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] packetId The packet ID to be serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * serializeSubscribeHeader( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId );
+/** @endcond */
+
+/**
+ * @fn uint8_t * serializeUnsubscribeHeader( uint32_t remainingLength, uint8_t * pIndex, uint16_t packetId );
+ * @brief Serialize the fixed part of the unsubscribe packet header.
+ *
+ * @param[in] remainingLength The remaining length of the packet to be
+ * serialized.
+ * @param[in] pIndex Pointer to the buffer where the header is to
+ * be serialized.
+ * @param[in] packetId The packet ID to be serialized.
+ *
+ * @return A pointer to the end of the encoded string.
+ */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this definition, this function is private.
+ */
+uint8_t * serializeUnsubscribeHeader( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId );
+/** @endcond */
+
+#endif /* ifndef CORE_MQTT_SERIALIZER_PRIVATE_H */
diff --git a/source/include/stdint.readme b/source/include/stdint.readme
index 75ca63161..7b071c4ee 100644
--- a/source/include/stdint.readme
+++ b/source/include/stdint.readme
@@ -34,4 +34,14 @@ typedef unsigned long long uint64_t;
#define INT64_MAX 9223372036854775807LL
#define UINT64_MAX 18446744073709551615ULL
+#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(__aarch64__) || defined(__64BIT__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8)
+ #define SIZE_MAX UINT64_MAX
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2
+ #define SIZE_MAX UINT16_MAX
+#elif defined(__AVR__) || defined(__MSP430__) || defined(__8051__) || defined(_M_I86)
+ #define SIZE_MAX UINT16_MAX
+#else
+ #define SIZE_MAX UINT32_MAX
+#endif
+
#endif /* _STDINT_H */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 675bce541..f6b8d33ce 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -26,8 +26,8 @@ if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
endif()
# Set global path variables.
-get_filename_component(__MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
-set(MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "coreMQTT repository root.")
+get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE )
+set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "coreMQTT repository root." )
# Configure options to always show in CMake GUI.
option( BUILD_CLONE_SUBMODULES
@@ -47,8 +47,8 @@ if( COV_ANALYSIS )
# Target for Coverity analysis that builds the library.
add_library( coverity_analysis
- ${MQTT_SOURCES}
- ${MQTT_SERIALIZER_SOURCES} )
+ ${MQTT_SOURCES}
+ ${MQTT_SERIALIZER_SOURCES} )
# Build MQTT library target without custom config dependency.
target_compile_definitions( coverity_analysis PUBLIC MQTT_DO_NOT_USE_CUSTOM_CONFIG=1 )
@@ -101,7 +101,7 @@ if( UNITTEST )
add_custom_target( coverage
COMMAND ${CMAKE_COMMAND} -DCMOCK_DIR=${CMOCK_DIR}
-P ${MODULE_ROOT_DIR}/tools/cmock/coverage.cmake
- DEPENDS cmock unity core_mqtt_utest core_mqtt_serializer_utest core_mqtt_state_utest
+ DEPENDS cmock unity core_mqtt_prop_serializer_utest core_mqtt_utest core_mqtt_serializer_utest core_mqtt_state_utest
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
diff --git a/test/cbmc/include/event_callback_stub.h b/test/cbmc/include/event_callback_stub.h
index 4c69541ad..7ca80cf85 100644
--- a/test/cbmc/include/event_callback_stub.h
+++ b/test/cbmc/include/event_callback_stub.h
@@ -40,8 +40,11 @@
* @param[in] pPacketInfo Information on the type of incoming MQTT packet.
* @param[in] pDeserializedInfo Deserialized information from incoming packet.
*/
-void EventCallbackStub( MQTTContext_t * pContext,
+bool EventCallbackStub( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
- MQTTDeserializedInfo_t * pDeserializedInfo );
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ enum MQTTSuccessFailReasonCode * pReasonCode,
+ struct MqttPropBuilder * pSendPropsBuffer,
+ struct MqttPropBuilder * pGetPropsBuffer );
#endif /* ifndef EVENT_CALLBACK_STUB_H_ */
diff --git a/test/cbmc/include/mqtt_cbmc_state.h b/test/cbmc/include/mqtt_cbmc_state.h
index 2929ca7e5..9a69d5714 100644
--- a/test/cbmc/include/mqtt_cbmc_state.h
+++ b/test/cbmc/include/mqtt_cbmc_state.h
@@ -119,6 +119,10 @@ MQTTFixedBuffer_t * allocateMqttFixedBuffer( MQTTFixedBuffer_t * pFixedBuffer );
*/
bool isValidMqttFixedBuffer( const MQTTFixedBuffer_t * pFixedBuffer );
+MQTTPropBuilder_t * allocateMqttPropBuilder( MQTTPropBuilder_t * pPropBuilder );
+
+bool isValidMqttPropBuilder( const MQTTPropBuilder_t * pPropBuilder );
+
/**
* @brief Allocate an array of #MQTTSubscribeInfo_t objects.
*
diff --git a/test/cbmc/proofs/DecodePubAckProperties/DecodePubAckProperties_harness.c b/test/cbmc/proofs/DecodePubAckProperties/DecodePubAckProperties_harness.c
new file mode 100644
index 000000000..d657427aa
--- /dev/null
+++ b/test/cbmc/proofs/DecodePubAckProperties/DecodePubAckProperties_harness.c
@@ -0,0 +1,72 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH 25U
+
+/* Here we assume the minimum size of a property can only be for a variable length
+ * integer property, e.g. subscription ID. Those will contain a 1 byte property ID,
+ * and a variable length integer. Due to this the maximum number of properties that
+ * will be in the packet will be MAX_PROPERTY_LENGTH / MIN_LENGTH_OF_SINGLE_PROPERTY.
+ */
+#define MIN_LENGTH_OF_SINGLE_PROPERTY ( 2U )
+
+#define MIN_REMAINING_LENGTH_FOR_ACK_WITHOUT_PROPS ( 2U )
+
+#ifndef REMAINING_LENGTH_MAX
+ #define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
+#endif
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * packetBytes;
+ uint32_t remainingLength;
+ size_t propertyLength;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ __CPROVER_assume( propertyLength >= 0 );
+ __CPROVER_assume( propertyLength <= MAX_PROPERTY_LENGTH );
+
+ remainingLength = MIN_REMAINING_LENGTH_FOR_ACK_WITHOUT_PROPS;
+ remainingLength += variableLengthEncodedSizeForProof( propertyLength ) + propertyLength;
+
+ packetBytes = malloc( remainingLength );
+ __CPROVER_assume( packetBytes != NULL );
+
+ encodeVariableLength( &packetBytes[ MIN_REMAINING_LENGTH_FOR_ACK_WITHOUT_PROPS ], propertyLength );
+
+ __CPROVER_file_local_core_mqtt_serializer_c_decodePubAckProperties( propBuffer, packetBytes, remainingLength );
+}
diff --git a/test/cbmc/proofs/DecodePubAckProperties/Makefile b/test/cbmc/proofs/DecodePubAckProperties/Makefile
new file mode 100644
index 000000000..5180a0c22
--- /dev/null
+++ b/test/cbmc/proofs/DecodePubAckProperties/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MQTT_INCOMING_MAX_PROPERTIES=14
+MAX_UTF_8_STRING_LENGTH=10
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=DecodePubAckProperties_harness
+PROOF_UID=DecodePubAckProperties
+
+DEFINES += -DMAX_UTF_8_STRING_LENGTH=$(MAX_UTF_8_STRING_LENGTH)
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += decodeUserProp
+REMOVE_FUNCTION_BODY += decodeUtf8
+REMOVE_FUNCTION_BODY += decodeUint8t
+REMOVE_FUNCTION_BODY += decodeUint32t
+UNWINDSET += decodeVariableLength.0:5
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_decodePubAckProperties.0:$(MQTT_INCOMING_MAX_PROPERTIES)
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/DecodePubAckProperties/README.md b/test/cbmc/proofs/DecodePubAckProperties/README.md
new file mode 100644
index 000000000..c87b3ee72
--- /dev/null
+++ b/test/cbmc/proofs/DecodePubAckProperties/README.md
@@ -0,0 +1,10 @@
+DecodePubAckProperties proof
+==============
+
+This directory contains a memory safety proof for DecodePubAckProperties.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_Connect/cbmc-proof.txt b/test/cbmc/proofs/DecodePubAckProperties/cbmc-proof.txt
similarity index 100%
rename from test/cbmc/proofs/MQTT_Connect/cbmc-proof.txt
rename to test/cbmc/proofs/DecodePubAckProperties/cbmc-proof.txt
diff --git a/test/cbmc/proofs/DecodePubAckProperties/cbmc-viewer.json b/test/cbmc/proofs/DecodePubAckProperties/cbmc-viewer.json
new file mode 100644
index 000000000..bf9869376
--- /dev/null
+++ b/test/cbmc/proofs/DecodePubAckProperties/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "DecodePubAckProperties",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/DeserializeConnackProperties/DeserializeConnackProperties_harness.c b/test/cbmc/proofs/DeserializeConnackProperties/DeserializeConnackProperties_harness.c
new file mode 100644
index 000000000..944531e6f
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeConnackProperties/DeserializeConnackProperties_harness.c
@@ -0,0 +1,71 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH 25U
+
+/* Here we assume the minimum size of a property can only be for a variable length
+ * integer property, e.g. subscription ID. Those will contain a 1 byte property ID,
+ * and a variable length integer. Due to this the maximum number of properties that
+ * will be in the packet will be MAX_PROPERTY_LENGTH / MIN_LENGTH_OF_SINGLE_PROPERTY.
+ */
+#define MIN_LENGTH_OF_SINGLE_PROPERTY ( 2U )
+
+#ifndef REMAINING_LENGTH_MAX
+ #define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
+#endif
+
+void harness()
+{
+ MQTTConnectionProperties_t * pConnectProperties;
+ size_t propertyLength;
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * packetBytes;
+
+ pConnectProperties = malloc( sizeof( MQTTConnectionProperties_t ) );
+ __CPROVER_assume( pConnectProperties != NULL );
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ __CPROVER_assume( propertyLength >= 0 );
+ __CPROVER_assume( propertyLength <= MAX_PROPERTY_LENGTH );
+
+ packetBytes = malloc( propertyLength + variableLengthEncodedSizeForProof( propertyLength ) );
+ __CPROVER_assume( packetBytes != NULL );
+
+ __CPROVER_file_local_core_mqtt_serializer_c_deserializeConnackProperties( pConnectProperties,
+ propertyLength,
+ packetBytes,
+ propBuffer );
+}
diff --git a/test/cbmc/proofs/DeserializeConnackProperties/Makefile b/test/cbmc/proofs/DeserializeConnackProperties/Makefile
new file mode 100644
index 000000000..76f37e40c
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeConnackProperties/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MAX_PROPERTY_LENGTH=14
+MAX_UTF_8_STRING_LENGTH=10
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=DeserializeConnackProperties_harness
+PROOF_UID=DeserializeConnackProperties
+
+DEFINES += -DMAX_UTF_8_STRING_LENGTH=$(MAX_UTF_8_STRING_LENGTH)
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += decodeUserProp
+REMOVE_FUNCTION_BODY += decodeUtf8
+REMOVE_FUNCTION_BODY += decodeUint8t
+REMOVE_FUNCTION_BODY += decodeUint32t
+
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_deserializeConnackProperties.0:$(MAX_PROPERTY_LENGTH)
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/DeserializeConnackProperties/README.md b/test/cbmc/proofs/DeserializeConnackProperties/README.md
new file mode 100644
index 000000000..53773a674
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeConnackProperties/README.md
@@ -0,0 +1,10 @@
+DeserializeConnackProperties proof
+==============
+
+This directory contains a memory safety proof for DeserializeConnackProperties.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_SerializeConnect/cbmc-proof.txt b/test/cbmc/proofs/DeserializeConnackProperties/cbmc-proof.txt
similarity index 100%
rename from test/cbmc/proofs/MQTT_SerializeConnect/cbmc-proof.txt
rename to test/cbmc/proofs/DeserializeConnackProperties/cbmc-proof.txt
diff --git a/test/cbmc/proofs/DeserializeConnackProperties/cbmc-viewer.json b/test/cbmc/proofs/DeserializeConnackProperties/cbmc-viewer.json
new file mode 100644
index 000000000..1a2b28c34
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeConnackProperties/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "DeserializeConnackProperties",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/DeserializeHelpers/DeserializeHelpers_harness.c b/test/cbmc/proofs/DeserializeHelpers/DeserializeHelpers_harness.c
new file mode 100644
index 000000000..9bea5ddde
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeHelpers/DeserializeHelpers_harness.c
@@ -0,0 +1,197 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+#ifndef REMAINING_LENGTH_MAX
+ #define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
+#endif
+
+void harness()
+{
+ uint8_t ** buffer;
+ size_t * length;
+ bool * used;
+ uint32_t * property_uint32_t;
+ uint32_t * property_uint16_t;
+ uint32_t * property_uint8_t;
+ const char ** property_utf_8;
+ const void ** property_binary;
+ uint16_t * property_length;
+
+ length = malloc( sizeof( size_t ) );
+
+ __CPROVER_assume( length != NULL );
+ __CPROVER_assume( *length >= 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( *length < REMAINING_LENGTH_MAX );
+
+ buffer = malloc( sizeof( uint8_t * ) );
+
+ __CPROVER_assume( buffer != NULL );
+
+ *buffer = malloc( *length );
+
+ __CPROVER_assume( *buffer != NULL );
+
+ const char * pPropertyKey, * pPropertyValue;
+ size_t PropertyKeyLen, PropertyValueLen;
+
+ decodeUserProp( &pPropertyKey,
+ &PropertyKeyLen,
+ &pPropertyValue,
+ &PropertyValueLen,
+ length,
+ buffer );
+
+ /*-----------------------------------------------------------*/
+
+ length = malloc( sizeof( size_t ) );
+
+ __CPROVER_assume( length != NULL );
+ __CPROVER_assume( *length >= 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( *length < REMAINING_LENGTH_MAX );
+
+ used = malloc( sizeof( bool ) );
+
+ __CPROVER_assume( used != NULL );
+
+ buffer = malloc( sizeof( uint8_t * ) );
+
+ __CPROVER_assume( buffer != NULL );
+
+ *buffer = malloc( *length );
+
+ __CPROVER_assume( *buffer != NULL );
+
+ const char * pProperty;
+ size_t PropertyLen;
+ decodeUtf8( &pProperty,
+ &PropertyLen,
+ length,
+ used,
+ buffer );
+
+ /*-----------------------------------------------------------*/
+
+ length = malloc( sizeof( size_t ) );
+
+ __CPROVER_assume( length != NULL );
+ __CPROVER_assume( *length >= 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( *length < REMAINING_LENGTH_MAX );
+
+ used = malloc( sizeof( bool ) );
+
+ __CPROVER_assume( used != NULL );
+
+ buffer = malloc( sizeof( uint8_t * ) );
+
+ __CPROVER_assume( buffer != NULL );
+
+ *buffer = malloc( *length );
+
+ __CPROVER_assume( *buffer != NULL );
+
+ uint8_t * u8Prop = malloc( sizeof( uint8_t ) );
+ decodeUint8t( u8Prop,
+ length,
+ used,
+ buffer );
+
+ /*-----------------------------------------------------------*/
+
+ length = malloc( sizeof( size_t ) );
+
+ __CPROVER_assume( length != NULL );
+ __CPROVER_assume( *length >= 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( *length < REMAINING_LENGTH_MAX );
+
+ used = malloc( sizeof( bool ) );
+
+ __CPROVER_assume( used != NULL );
+
+ buffer = malloc( sizeof( uint8_t * ) );
+
+ __CPROVER_assume( buffer != NULL );
+
+ *buffer = malloc( *length );
+
+ __CPROVER_assume( *buffer != NULL );
+
+ uint32_t * u32Property = malloc( sizeof( uint32_t ) );
+ decodeUint32t( u32Property,
+ length,
+ used,
+ buffer );
+
+ /*-----------------------------------------------------------*/
+
+ property_uint32_t = malloc( sizeof( uint32_t ) );
+
+ __CPROVER_assume( property_uint32_t != NULL );
+
+ length = malloc( sizeof( size_t ) );
+
+ __CPROVER_assume( length != NULL );
+ __CPROVER_assume( *length >= 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( *length < REMAINING_LENGTH_MAX );
+
+ used = malloc( sizeof( bool ) );
+
+ __CPROVER_assume( used != NULL );
+
+ buffer = malloc( sizeof( uint8_t * ) );
+
+ __CPROVER_assume( buffer != NULL );
+
+ *buffer = malloc( *length );
+
+ __CPROVER_assume( *buffer != NULL );
+
+ uint16_t * u16Property = malloc( sizeof( uint16_t ) );
+ decodeUint16t( u16Property,
+ length,
+ used,
+ buffer );
+}
diff --git a/test/cbmc/proofs/DeserializeHelpers/Makefile b/test/cbmc/proofs/DeserializeHelpers/Makefile
new file mode 100644
index 000000000..7d7c2b8d7
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeHelpers/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MQTT_INCOMING_PUBLISH_MAX_PROPERTIES=2
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=DeserializeHelpers_harness
+PROOF_UID=DeserializeHelpers
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/DeserializeHelpers/README.md b/test/cbmc/proofs/DeserializeHelpers/README.md
new file mode 100644
index 000000000..087dad65a
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeHelpers/README.md
@@ -0,0 +1,10 @@
+DeserializeHelpers proof
+==============
+
+This directory contains a memory safety proof for DeserializeHelpers.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/DeserializeHelpers/cbmc-proof.txt b/test/cbmc/proofs/DeserializeHelpers/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeHelpers/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/DeserializeHelpers/cbmc-viewer.json b/test/cbmc/proofs/DeserializeHelpers/cbmc-viewer.json
new file mode 100644
index 000000000..9acdee648
--- /dev/null
+++ b/test/cbmc/proofs/DeserializeHelpers/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "DeserializeHelpers",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/DeserializePublishProperties/DeserializePublishProperties_harness.c b/test/cbmc/proofs/DeserializePublishProperties/DeserializePublishProperties_harness.c
new file mode 100644
index 000000000..307de8672
--- /dev/null
+++ b/test/cbmc/proofs/DeserializePublishProperties/DeserializePublishProperties_harness.c
@@ -0,0 +1,86 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH 25U
+
+/* Here we assume the minimum size of a property can only be for a variable length
+ * integer property, e.g. subscription ID. Those will contain a 1 byte property ID,
+ * and a variable length integer. Due to this the maximum number of properties that
+ * will be in the packet will be MAX_PROPERTY_LENGTH / MIN_LENGTH_OF_SINGLE_PROPERTY.
+ */
+#define MIN_LENGTH_OF_SINGLE_PROPERTY ( 2U )
+
+#ifndef REMAINING_LENGTH_MAX
+ #define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
+#endif
+
+void harness()
+{
+ MQTTPublishInfo_t * pPublishInfo;
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t topicAliasMax;
+ uint8_t * packetBytes;
+ size_t propertyLength;
+ size_t maxPropertyLength;
+ size_t minRemainingLength;
+ uint32_t remainingLength;
+
+ pPublishInfo = allocateMqttPublishInfo( NULL );
+ __CPROVER_assume( isValidMqttPublishInfo( pPublishInfo ) );
+ __CPROVER_assume( pPublishInfo != NULL );
+ __CPROVER_assume( pPublishInfo->topicNameLength != 0 );
+ __CPROVER_assume( pPublishInfo->topicNameLength <= UINT16_MAX );
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ maxPropertyLength = MAX_PROPERTY_LENGTH;
+
+ __CPROVER_assume( propertyLength >= 0 );
+ __CPROVER_assume( propertyLength <= maxPropertyLength );
+
+ minRemainingLength = pPublishInfo->topicNameLength + sizeof( uint16_t );
+ minRemainingLength += ( pPublishInfo->qos > MQTTQoS0 ) ? 2 : 0;
+ minRemainingLength += propertyLength + variableLengthEncodedSizeForProof( propertyLength );
+
+ __CPROVER_assume( remainingLength >= minRemainingLength );
+ __CPROVER_assume( remainingLength < REMAINING_LENGTH_MAX );
+
+ packetBytes = malloc( remainingLength - ( minRemainingLength - propertyLength - ( 4 * sizeof( uint8_t ) ) ) );
+ __CPROVER_assume( packetBytes != NULL );
+
+ encodeVariableLength( packetBytes, propertyLength );
+
+ __CPROVER_file_local_core_mqtt_serializer_c_deserializePublishProperties( pPublishInfo, propBuffer, packetBytes, topicAliasMax, remainingLength );
+}
diff --git a/test/cbmc/proofs/DeserializePublishProperties/Makefile b/test/cbmc/proofs/DeserializePublishProperties/Makefile
new file mode 100644
index 000000000..85a22c08b
--- /dev/null
+++ b/test/cbmc/proofs/DeserializePublishProperties/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MQTT_INCOMING_PUBLISH_MAX_PROPERTIES=14
+MAX_UTF_8_STRING_LENGTH=10
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=DeserializePublishProperties_harness
+PROOF_UID=DeserializePublishProperties
+
+DEFINES += -DMAX_UTF_8_STRING_LENGTH=$(MAX_UTF_8_STRING_LENGTH)
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += decodeUserProp
+REMOVE_FUNCTION_BODY += decodeUtf8
+REMOVE_FUNCTION_BODY += decodeUint8t
+REMOVE_FUNCTION_BODY += decodeUint32t
+
+UNWINDSET += encodeVariableLength.0:5
+UNWINDSET += decodeVariableLength.0:5
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_deserializePublishProperties.0:$(MQTT_INCOMING_PUBLISH_MAX_PROPERTIES)
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/DeserializePublishProperties/README.md b/test/cbmc/proofs/DeserializePublishProperties/README.md
new file mode 100644
index 000000000..49c8f28be
--- /dev/null
+++ b/test/cbmc/proofs/DeserializePublishProperties/README.md
@@ -0,0 +1,10 @@
+DeserializePublishProperties proof
+==============
+
+This directory contains a memory safety proof for DeserializePublishProperties.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/DeserializePublishProperties/cbmc-proof.txt b/test/cbmc/proofs/DeserializePublishProperties/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/DeserializePublishProperties/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/DeserializePublishProperties/cbmc-viewer.json b/test/cbmc/proofs/DeserializePublishProperties/cbmc-viewer.json
new file mode 100644
index 000000000..65286debd
--- /dev/null
+++ b/test/cbmc/proofs/DeserializePublishProperties/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "DeserializePublishProperties",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AssignedClientId/MQTTPropGet_AssignedClientId_harness.c b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/MQTTPropGet_AssignedClientId_harness.c
new file mode 100644
index 000000000..77ec0de91
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/MQTTPropGet_AssignedClientId_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pClientId;
+ size_t * clientIdLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pClientId = malloc( sizeof( char * ) );
+ clientIdLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_AssignedClientId( propBuffer, ¤tIndex, pClientId, clientIdLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AssignedClientId/Makefile b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/Makefile
new file mode 100644
index 000000000..0c22fa8d6
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_AssignedClientId_harness
+PROOF_UID=MQTTPropGet_AssignedClientId
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_AssignedClientId/README.md b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/README.md
new file mode 100644
index 000000000..368ea063c
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_AssignedClientId proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_AssignedClientId.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-viewer.json
new file mode 100644
index 000000000..cbf28f404
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AssignedClientId/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_AssignedClientId",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthData/MQTTPropGet_AuthData_harness.c b/test/cbmc/proofs/MQTTPropGet_AuthData/MQTTPropGet_AuthData_harness.c
new file mode 100644
index 000000000..3d94372cb
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthData/MQTTPropGet_AuthData_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pAuthData;
+ size_t * authDataLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pAuthData = malloc( sizeof( char * ) );
+ authDataLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_AuthData( propBuffer, ¤tIndex, pAuthData, authDataLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthData/Makefile b/test/cbmc/proofs/MQTTPropGet_AuthData/Makefile
new file mode 100644
index 000000000..555c4210b
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthData/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_AuthData_harness
+PROOF_UID=MQTTPropGet_AuthData
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthData/README.md b/test/cbmc/proofs/MQTTPropGet_AuthData/README.md
new file mode 100644
index 000000000..9b06f4c69
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthData/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_AuthData proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_AuthData.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-viewer.json
new file mode 100644
index 000000000..3ea379644
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthData/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_AuthData",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthMethod/MQTTPropGet_AuthMethod_harness.c b/test/cbmc/proofs/MQTTPropGet_AuthMethod/MQTTPropGet_AuthMethod_harness.c
new file mode 100644
index 000000000..4e0708f60
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthMethod/MQTTPropGet_AuthMethod_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pAuthMethod;
+ size_t * authMethodLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pAuthMethod = malloc( sizeof( char * ) );
+ authMethodLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_AuthMethod( propBuffer, ¤tIndex, pAuthMethod, authMethodLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthMethod/Makefile b/test/cbmc/proofs/MQTTPropGet_AuthMethod/Makefile
new file mode 100644
index 000000000..ed5dd8efe
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthMethod/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_AuthMethod_harness
+PROOF_UID=MQTTPropGet_AuthMethod
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthMethod/README.md b/test/cbmc/proofs/MQTTPropGet_AuthMethod/README.md
new file mode 100644
index 000000000..0f6aaaeec
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthMethod/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_AuthMethod proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_AuthMethod.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-viewer.json
new file mode 100644
index 000000000..da535602d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_AuthMethod/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_AuthMethod",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ContentType/MQTTPropGet_ContentType_harness.c b/test/cbmc/proofs/MQTTPropGet_ContentType/MQTTPropGet_ContentType_harness.c
new file mode 100644
index 000000000..b4f5c7093
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ContentType/MQTTPropGet_ContentType_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pContentType;
+ size_t * contentTypeLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pContentType = malloc( sizeof( char * ) );
+ contentTypeLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_ContentType( propBuffer, ¤tIndex, pContentType, contentTypeLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ContentType/Makefile b/test/cbmc/proofs/MQTTPropGet_ContentType/Makefile
new file mode 100644
index 000000000..3dac7ead6
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ContentType/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ContentType_harness
+PROOF_UID=MQTTPropGet_ContentType
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ContentType/README.md b/test/cbmc/proofs/MQTTPropGet_ContentType/README.md
new file mode 100644
index 000000000..c4b9b7dc8
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ContentType/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ContentType proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ContentType.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-viewer.json
new file mode 100644
index 000000000..75f912198
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ContentType/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ContentType",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_CorrelationData/MQTTPropGet_CorrelationData_harness.c b/test/cbmc/proofs/MQTTPropGet_CorrelationData/MQTTPropGet_CorrelationData_harness.c
new file mode 100644
index 000000000..639b4cc34
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_CorrelationData/MQTTPropGet_CorrelationData_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** correlationData;
+ size_t * correlationLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ correlationData = malloc( sizeof( char * ) );
+ correlationLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_CorrelationData( propBuffer, ¤tIndex, correlationData, correlationLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_CorrelationData/Makefile b/test/cbmc/proofs/MQTTPropGet_CorrelationData/Makefile
new file mode 100644
index 000000000..9f6e5f7c1
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_CorrelationData/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_CorrelationData_harness
+PROOF_UID=MQTTPropGet_CorrelationData
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_CorrelationData/README.md b/test/cbmc/proofs/MQTTPropGet_CorrelationData/README.md
new file mode 100644
index 000000000..d19182a0d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_CorrelationData/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_CorrelationData proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_CorrelationData.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-viewer.json
new file mode 100644
index 000000000..b22a6e05a
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_CorrelationData/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_CorrelationData",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/MQTTPropGet_MaxPacketSize_harness.c b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/MQTTPropGet_MaxPacketSize_harness.c
new file mode 100644
index 000000000..d64ad0d21
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/MQTTPropGet_MaxPacketSize_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint32_t * maxPacketSize;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ maxPacketSize = malloc( sizeof( uint32_t ) );
+
+ MQTTPropGet_MaxPacketSize( propBuffer, ¤tIndex, maxPacketSize );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/Makefile b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/Makefile
new file mode 100644
index 000000000..fac0c0ed9
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_MaxPacketSize_harness
+PROOF_UID=MQTTPropGet_MaxPacketSize
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/README.md b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/README.md
new file mode 100644
index 000000000..b8f83e25d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_MaxPacketSize proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_MaxPacketSize.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-viewer.json
new file mode 100644
index 000000000..297817962
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxPacketSize/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_MaxPacketSize",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxQos/MQTTPropGet_MaxQos_harness.c b/test/cbmc/proofs/MQTTPropGet_MaxQos/MQTTPropGet_MaxQos_harness.c
new file mode 100644
index 000000000..5fc11921b
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxQos/MQTTPropGet_MaxQos_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * maxQos;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ maxQos = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_MaxQos( propBuffer, ¤tIndex, maxQos );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxQos/Makefile b/test/cbmc/proofs/MQTTPropGet_MaxQos/Makefile
new file mode 100644
index 000000000..86fc87a41
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxQos/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_MaxQos_harness
+PROOF_UID=MQTTPropGet_MaxQos
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxQos/README.md b/test/cbmc/proofs/MQTTPropGet_MaxQos/README.md
new file mode 100644
index 000000000..4b390efa9
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxQos/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_MaxQos proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_MaxQos.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-viewer.json
new file mode 100644
index 000000000..95129d148
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MaxQos/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_MaxQos",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/MQTTPropGet_MessageExpiryInterval_harness.c b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/MQTTPropGet_MessageExpiryInterval_harness.c
new file mode 100644
index 000000000..2367bc0d6
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/MQTTPropGet_MessageExpiryInterval_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint32_t * msgExpiryInterval;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ msgExpiryInterval = malloc( sizeof( uint32_t ) );
+
+ MQTTPropGet_MessageExpiryInterval( propBuffer, ¤tIndex, msgExpiryInterval );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/Makefile b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/Makefile
new file mode 100644
index 000000000..374dce5f1
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_MessageExpiryInterval_harness
+PROOF_UID=MQTTPropGet_MessageExpiryInterval
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/README.md b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/README.md
new file mode 100644
index 000000000..a9084822b
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_MessageExpiryInterval proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_MessageExpiryInterval.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-viewer.json
new file mode 100644
index 000000000..5071936ea
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_MessageExpiryInterval/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_MessageExpiryInterval",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/MQTTPropGet_PayloadFormatIndicator_harness.c b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/MQTTPropGet_PayloadFormatIndicator_harness.c
new file mode 100644
index 000000000..4434a1783
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/MQTTPropGet_PayloadFormatIndicator_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * payloadFormat;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ payloadFormat = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_PayloadFormatIndicator( propBuffer, ¤tIndex, payloadFormat );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/Makefile b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/Makefile
new file mode 100644
index 000000000..2127b9187
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_PayloadFormatIndicator_harness
+PROOF_UID=MQTTPropGet_PayloadFormatIndicator
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/README.md b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/README.md
new file mode 100644
index 000000000..3fdaf82be
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_PayloadFormatIndicator proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_PayloadFormatIndicator.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-viewer.json
new file mode 100644
index 000000000..f0b85f436
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_PayloadFormatIndicator/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_PayloadFormatIndicator",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ReasonString/MQTTPropGet_ReasonString_harness.c b/test/cbmc/proofs/MQTTPropGet_ReasonString/MQTTPropGet_ReasonString_harness.c
new file mode 100644
index 000000000..1b546c07d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReasonString/MQTTPropGet_ReasonString_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pReasonString;
+ uint16_t * reasonStringLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pReasonString = malloc( sizeof( char * ) );
+ reasonStringLength = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_ReasonString( propBuffer, ¤tIndex, pReasonString, reasonStringLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ReasonString/Makefile b/test/cbmc/proofs/MQTTPropGet_ReasonString/Makefile
new file mode 100644
index 000000000..7316928d2
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReasonString/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ReasonString_harness
+PROOF_UID=MQTTPropGet_ReasonString
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ReasonString/README.md b/test/cbmc/proofs/MQTTPropGet_ReasonString/README.md
new file mode 100644
index 000000000..9afe372e4
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReasonString/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ReasonString proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ReasonString.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-viewer.json
new file mode 100644
index 000000000..144c6bc08
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReasonString/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ReasonString",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ReceiveMax/MQTTPropGet_ReceiveMax_harness.c b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/MQTTPropGet_ReceiveMax_harness.c
new file mode 100644
index 000000000..51bbd9dc7
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/MQTTPropGet_ReceiveMax_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t * receiveMax;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ receiveMax = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_ReceiveMax( propBuffer, ¤tIndex, receiveMax );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ReceiveMax/Makefile b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/Makefile
new file mode 100644
index 000000000..530e87433
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ReceiveMax_harness
+PROOF_UID=MQTTPropGet_ReceiveMax
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ReceiveMax/README.md b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/README.md
new file mode 100644
index 000000000..31923dc65
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ReceiveMax proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ReceiveMax.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-viewer.json
new file mode 100644
index 000000000..c9f38d5f8
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ReceiveMax/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ReceiveMax",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseInfo/MQTTPropGet_ResponseInfo_harness.c b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/MQTTPropGet_ResponseInfo_harness.c
new file mode 100644
index 000000000..8c51d2112
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/MQTTPropGet_ResponseInfo_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pResponseInfo;
+ uint16_t * responseInfoLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pResponseInfo = malloc( sizeof( char * ) );
+ responseInfoLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_ResponseInfo( propBuffer, ¤tIndex, pResponseInfo, responseInfoLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseInfo/Makefile b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/Makefile
new file mode 100644
index 000000000..6690503c1
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ResponseInfo_harness
+PROOF_UID=MQTTPropGet_ResponseInfo
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseInfo/README.md b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/README.md
new file mode 100644
index 000000000..943d26879
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ResponseInfo proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ResponseInfo.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-viewer.json
new file mode 100644
index 000000000..78c363999
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseInfo/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ResponseInfo",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseTopic/MQTTPropGet_ResponseTopic_harness.c b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/MQTTPropGet_ResponseTopic_harness.c
new file mode 100644
index 000000000..854048dbe
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/MQTTPropGet_ResponseTopic_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** responseTopic;
+ uint16_t * responseTopicLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ responseTopic = malloc( sizeof( char * ) );
+ responseTopicLength = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_ResponseTopic( propBuffer, ¤tIndex, responseTopic, responseTopicLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseTopic/Makefile b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/Makefile
new file mode 100644
index 000000000..0b7929d9e
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ResponseTopic_harness
+PROOF_UID=MQTTPropGet_ResponseTopic
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseTopic/README.md b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/README.md
new file mode 100644
index 000000000..9e770fbd8
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ResponseTopic proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ResponseTopic.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-viewer.json
new file mode 100644
index 000000000..f308a41ca
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ResponseTopic/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ResponseTopic",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_RetainAvailable/MQTTPropGet_RetainAvailable_harness.c b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/MQTTPropGet_RetainAvailable_harness.c
new file mode 100644
index 000000000..e089cf14a
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/MQTTPropGet_RetainAvailable_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * retainAvailable;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ retainAvailable = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_RetainAvailable( propBuffer, ¤tIndex, retainAvailable );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_RetainAvailable/Makefile b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/Makefile
new file mode 100644
index 000000000..2537e913f
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_RetainAvailable_harness
+PROOF_UID=MQTTPropGet_RetainAvailable
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_RetainAvailable/README.md b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/README.md
new file mode 100644
index 000000000..14b3e1f9f
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_RetainAvailable proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_RetainAvailable.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-viewer.json
new file mode 100644
index 000000000..37ffe6867
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_RetainAvailable/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_RetainAvailable",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/MQTTPropGet_ServerKeepAlive_harness.c b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/MQTTPropGet_ServerKeepAlive_harness.c
new file mode 100644
index 000000000..0004c1ae5
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/MQTTPropGet_ServerKeepAlive_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t * serverKeepAlive;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ serverKeepAlive = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_ServerKeepAlive( propBuffer, ¤tIndex, serverKeepAlive );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/Makefile b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/Makefile
new file mode 100644
index 000000000..a0f6107ac
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ServerKeepAlive_harness
+PROOF_UID=MQTTPropGet_ServerKeepAlive
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/README.md b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/README.md
new file mode 100644
index 000000000..8b4b7c5bf
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ServerKeepAlive proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ServerKeepAlive.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-viewer.json
new file mode 100644
index 000000000..224f2af72
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerKeepAlive/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ServerKeepAlive",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerRef/MQTTPropGet_ServerRef_harness.c b/test/cbmc/proofs/MQTTPropGet_ServerRef/MQTTPropGet_ServerRef_harness.c
new file mode 100644
index 000000000..d61e71c04
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerRef/MQTTPropGet_ServerRef_harness.c
@@ -0,0 +1,53 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ char ** pServerRef;
+ uint16_t * serverRefLength;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ pServerRef = malloc( sizeof( char * ) );
+ serverRefLength = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_ServerRef( propBuffer, ¤tIndex, pServerRef, serverRefLength );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerRef/Makefile b/test/cbmc/proofs/MQTTPropGet_ServerRef/Makefile
new file mode 100644
index 000000000..46e7d4a69
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerRef/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_ServerRef_harness
+PROOF_UID=MQTTPropGet_ServerRef
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerRef/README.md b/test/cbmc/proofs/MQTTPropGet_ServerRef/README.md
new file mode 100644
index 000000000..ad9473bcf
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerRef/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_ServerRef proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_ServerRef.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-viewer.json
new file mode 100644
index 000000000..b2dac9c91
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_ServerRef/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_ServerRef",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SessionExpiry/MQTTPropGet_SessionExpiry_harness.c b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/MQTTPropGet_SessionExpiry_harness.c
new file mode 100644
index 000000000..40686f8c0
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/MQTTPropGet_SessionExpiry_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint32_t * sessionExpiry;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ sessionExpiry = malloc( sizeof( uint32_t ) );
+
+ MQTTPropGet_SessionExpiry( propBuffer, ¤tIndex, sessionExpiry );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SessionExpiry/Makefile b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/Makefile
new file mode 100644
index 000000000..6fdc7d1b3
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_SessionExpiry_harness
+PROOF_UID=MQTTPropGet_SessionExpiry
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_SessionExpiry/README.md b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/README.md
new file mode 100644
index 000000000..455f7e6c2
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_SessionExpiry proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_SessionExpiry.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-viewer.json
new file mode 100644
index 000000000..32822aa92
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SessionExpiry/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_SessionExpiry",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/MQTTPropGet_SharedSubAvailable_harness.c b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/MQTTPropGet_SharedSubAvailable_harness.c
new file mode 100644
index 000000000..97f20f959
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/MQTTPropGet_SharedSubAvailable_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * isSharedSubAvailable;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ isSharedSubAvailable = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_SharedSubAvailable( propBuffer, ¤tIndex, isSharedSubAvailable );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/Makefile b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/Makefile
new file mode 100644
index 000000000..e0dcc1d2d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_SharedSubAvailable_harness
+PROOF_UID=MQTTPropGet_SharedSubAvailable
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/README.md b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/README.md
new file mode 100644
index 000000000..73130aa45
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_SharedSubAvailable proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_SharedSubAvailable.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-viewer.json
new file mode 100644
index 000000000..b848ce28e
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SharedSubAvailable/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_SharedSubAvailable",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/MQTTPropGet_SubsIdAvailable_harness.c b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/MQTTPropGet_SubsIdAvailable_harness.c
new file mode 100644
index 000000000..17481a264
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/MQTTPropGet_SubsIdAvailable_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * isSubIdAvailable;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ isSubIdAvailable = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_SubsIdAvailable( propBuffer, ¤tIndex, isSubIdAvailable );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/Makefile b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/Makefile
new file mode 100644
index 000000000..45968db6b
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_SubsIdAvailable_harness
+PROOF_UID=MQTTPropGet_SubsIdAvailable
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/README.md b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/README.md
new file mode 100644
index 000000000..df551efb5
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_SubsIdAvailable proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_SubsIdAvailable.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-viewer.json
new file mode 100644
index 000000000..cd579b11d
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubsIdAvailable/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_SubsIdAvailable",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SubscriptionId/MQTTPropGet_SubscriptionId_harness.c b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/MQTTPropGet_SubscriptionId_harness.c
new file mode 100644
index 000000000..5109f2712
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/MQTTPropGet_SubscriptionId_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ size_t * subscriptionId;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ subscriptionId = malloc( sizeof( size_t ) );
+
+ MQTTPropGet_SubscriptionId( propBuffer, ¤tIndex, subscriptionId );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_SubscriptionId/Makefile b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/Makefile
new file mode 100644
index 000000000..65d4c7b88
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_SubscriptionId_harness
+PROOF_UID=MQTTPropGet_SubscriptionId
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET += decodeVariableLength.0:5
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_SubscriptionId/README.md b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/README.md
new file mode 100644
index 000000000..ec0b41db2
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_SubscriptionId proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_SubscriptionId.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-viewer.json
new file mode 100644
index 000000000..e5739ee4e
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_SubscriptionId/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_SubscriptionId",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAlias/MQTTPropGet_TopicAlias_harness.c b/test/cbmc/proofs/MQTTPropGet_TopicAlias/MQTTPropGet_TopicAlias_harness.c
new file mode 100644
index 000000000..e4ad7d1ec
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAlias/MQTTPropGet_TopicAlias_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t * topicAlias;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ topicAlias = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_TopicAlias( propBuffer, ¤tIndex, topicAlias );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAlias/Makefile b/test/cbmc/proofs/MQTTPropGet_TopicAlias/Makefile
new file mode 100644
index 000000000..2fd86d051
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAlias/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_TopicAlias_harness
+PROOF_UID=MQTTPropGet_TopicAlias
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAlias/README.md b/test/cbmc/proofs/MQTTPropGet_TopicAlias/README.md
new file mode 100644
index 000000000..841e3476e
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAlias/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_TopicAlias proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_TopicAlias.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-viewer.json
new file mode 100644
index 000000000..e462d4ea3
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAlias/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_TopicAlias",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/MQTTPropGet_TopicAliasMax_harness.c b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/MQTTPropGet_TopicAliasMax_harness.c
new file mode 100644
index 000000000..2d0bdbc77
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/MQTTPropGet_TopicAliasMax_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t * topicAliasMax;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ topicAliasMax = malloc( sizeof( uint16_t ) );
+
+ MQTTPropGet_TopicAliasMax( propBuffer, ¤tIndex, topicAliasMax );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/Makefile b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/Makefile
new file mode 100644
index 000000000..4008366ff
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_TopicAliasMax_harness
+PROOF_UID=MQTTPropGet_TopicAliasMax
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/README.md b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/README.md
new file mode 100644
index 000000000..395e71b16
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_TopicAliasMax proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_TopicAliasMax.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-viewer.json
new file mode 100644
index 000000000..3da526b8b
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_TopicAliasMax/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_TopicAliasMax",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_UserProp/MQTTPropGet_UserProp_harness.c b/test/cbmc/proofs/MQTTPropGet_UserProp/MQTTPropGet_UserProp_harness.c
new file mode 100644
index 000000000..d97c498b8
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_UserProp/MQTTPropGet_UserProp_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ size_t currentIndex;
+ MQTTUserProperty_t pUserProperty;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ MQTTPropGet_UserProp( propBuffer,
+ ¤tIndex,
+ &pUserProperty );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_UserProp/Makefile b/test/cbmc/proofs/MQTTPropGet_UserProp/Makefile
new file mode 100644
index 000000000..d70ade4f8
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_UserProp/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_UserProp_harness
+PROOF_UID=MQTTPropGet_UserProp
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_UserProp/README.md b/test/cbmc/proofs/MQTTPropGet_UserProp/README.md
new file mode 100644
index 000000000..9dbf54dae
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_UserProp/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_UserProp proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_UserProp.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-viewer.json
new file mode 100644
index 000000000..7c6818d45
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_UserProp/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_UserProp",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_WildcardId/MQTTPropGet_WildcardId_harness.c b/test/cbmc/proofs/MQTTPropGet_WildcardId/MQTTPropGet_WildcardId_harness.c
new file mode 100644
index 000000000..4b9a6c720
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_WildcardId/MQTTPropGet_WildcardId_harness.c
@@ -0,0 +1,51 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * isWildCardAvailable;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ isWildCardAvailable = malloc( sizeof( uint8_t ) );
+
+ MQTTPropGet_WildcardId( propBuffer, ¤tIndex, isWildCardAvailable );
+}
diff --git a/test/cbmc/proofs/MQTTPropGet_WildcardId/Makefile b/test/cbmc/proofs/MQTTPropGet_WildcardId/Makefile
new file mode 100644
index 000000000..95d3f869e
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_WildcardId/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTTPropGet_WildcardId_harness
+PROOF_UID=MQTTPropGet_WildcardId
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTTPropGet_WildcardId/README.md b/test/cbmc/proofs/MQTTPropGet_WildcardId/README.md
new file mode 100644
index 000000000..ef9e33750
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_WildcardId/README.md
@@ -0,0 +1,10 @@
+MQTTPropGet_WildcardId proof
+==============
+
+This directory contains a memory safety proof for MQTTPropGet_WildcardId.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-proof.txt b/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-viewer.json b/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-viewer.json
new file mode 100644
index 000000000..d2ddb4ed9
--- /dev/null
+++ b/test/cbmc/proofs/MQTTPropGet_WildcardId/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTTPropGet_WildcardId",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTT_Connect/MQTT_Connect_harness.c b/test/cbmc/proofs/MQTT_Connect/MQTT_Connect_harness.c
index 1ab176f09..df362f934 100644
--- a/test/cbmc/proofs/MQTT_Connect/MQTT_Connect_harness.c
+++ b/test/cbmc/proofs/MQTT_Connect/MQTT_Connect_harness.c
@@ -30,6 +30,10 @@
#include "mqtt_cbmc_state.h"
#include "core_mqtt_config_defaults.h"
+#include "network_interface_stubs.h"
+#include "get_time_stub.h"
+#include "event_callback_stub.h"
+
/**
* @brief Implement a get time function to return timeout after certain
* iterations have been made in the code. This ensures that we do not hit
@@ -43,7 +47,8 @@ static uint32_t ulGetTimeFunction( void )
{
static uint32_t systemTime = 0;
- if( systemTime >= MAX_NETWORK_SEND_TRIES )
+ if( systemTime >= ( ( MAX_NETWORK_SEND_TRIES * 2 ) + 1 ) )
+ /* if( systemTime >= MAX_NETWORK_SEND_TRIES ) */
{
systemTime = systemTime + MQTT_SEND_TIMEOUT_MS + 1;
}
@@ -55,11 +60,54 @@ static uint32_t ulGetTimeFunction( void )
return systemTime;
}
+uint8_t * serializeConnectFixedHeader( uint8_t * pIndex,
+ const MQTTConnectInfo_t * pConnectInfo,
+ const MQTTPublishInfo_t * pWillInfo,
+ uint32_t remainingLength )
+{
+ __CPROVER_assert( pIndex != NULL, "pIndex must not be NULL." );
+ __CPROVER_assert( pConnectInfo != NULL, "pConnectInfo must not be NULL." );
+
+ uint8_t value;
+
+ __CPROVER_assume( value >= 0 );
+ __CPROVER_assume( value < 15 );
+
+ return &pIndex[ value ];
+}
+
+MQTTStatus_t updateContextWithConnectProps( const MQTTPropBuilder_t * pPropBuilder,
+ MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
+MQTTStatus_t MQTT_ValidateWillProperties( const MQTTPropBuilder_t * pPropertyBuilder )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
+MQTTStatus_t MQTT_DeserializeConnAck( const MQTTPacketInfo_t * pIncomingPacket,
+ bool * pSessionPresent,
+ MQTTPropBuilder_t * pPropBuffer,
+ MQTTConnectionProperties_t * pConnectProperties )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
void harness()
{
MQTTContext_t * pContext;
MQTTConnectInfo_t * pConnectInfo;
MQTTPublishInfo_t * pWillInfo;
+ MQTTPropBuilder_t * pPropertyBuilder;
+ MQTTPropBuilder_t * willPropsBuilder;
uint32_t timeoutMs;
size_t totalMessageLength = 0U;
bool * pSessionPresent;
@@ -144,6 +192,30 @@ void harness()
totalMessageLength += pWillInfo->payloadLength;
}
+ pPropertyBuilder = allocateMqttPropBuilder( NULL );
+
+ if( pPropertyBuilder != NULL )
+ {
+ __CPROVER_assume( pPropertyBuilder->currentIndex >= 0 );
+ __CPROVER_assume( pPropertyBuilder->currentIndex < pPropertyBuilder->bufferLength );
+ __CPROVER_assume( pPropertyBuilder->fieldSet >= 0 );
+ }
+
+ __CPROVER_assume( isValidMqttPropBuilder( pPropertyBuilder ) );
+
+ willPropsBuilder = allocateMqttPropBuilder( NULL );
+
+ if( willPropsBuilder != NULL )
+ {
+ __CPROVER_assume( willPropsBuilder->currentIndex >= 0 );
+ __CPROVER_assume( willPropsBuilder->currentIndex < willPropsBuilder->bufferLength );
+ __CPROVER_assume( willPropsBuilder->fieldSet >= 0 );
+
+ totalMessageLength += willPropsBuilder->currentIndex;
+ }
+
+ __CPROVER_assume( isValidMqttPropBuilder( willPropsBuilder ) );
+
/* 128^4 is the length imposed by the MQTT spec. */
__CPROVER_assume( totalMessageLength <= 268435456 );
@@ -154,5 +226,5 @@ void harness()
* safety can be proven in only a few iterations. */
__CPROVER_assume( timeoutMs < MQTT_RECEIVE_TIMEOUT );
- MQTT_Connect( pContext, pConnectInfo, pWillInfo, timeoutMs, pSessionPresent );
+ MQTT_Connect( pContext, pConnectInfo, pWillInfo, timeoutMs, pSessionPresent, pPropertyBuilder, willPropsBuilder );
}
diff --git a/test/cbmc/proofs/MQTT_Connect/Makefile b/test/cbmc/proofs/MQTT_Connect/Makefile
index 13ae71f3e..873e0c354 100644
--- a/test/cbmc/proofs/MQTT_Connect/Makefile
+++ b/test/cbmc/proofs/MQTT_Connect/Makefile
@@ -25,7 +25,7 @@ PROOF_UID=MQTT_Connect
# Please see test/cbmc/stubs/network_interface_subs.c for
# more information on MAX_NETWORK_SEND_TRIES.
-MAX_NETWORK_SEND_TRIES=3
+MAX_NETWORK_SEND_TRIES=4
# Bound on the timeout in receiveConnack. This timeout is bounded because
# memory saftey can be proven in a only a few iteration of the MQTT operations.
# Each iteration will try to receive a single packet in its entirety. With a
@@ -40,7 +40,7 @@ MAX_NETWORK_RECV_TRIES=4
# information on these defines.
MQTT_STATE_ARRAY_MAX_COUNT=11
MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT=3
-CONNECT_PACKET_VECTORS = 12
+CONNECT_PACKET_VECTORS = 16
DEFINES += -DMQTT_RECEIVE_TIMEOUT=$(MQTT_RECEIVE_TIMEOUT)
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
DEFINES += -DMAX_NETWORK_RECV_TRIES=$(MAX_NETWORK_RECV_TRIES)
@@ -53,8 +53,10 @@ REMOVE_FUNCTION_BODY += MQTT_ProcessLoop
REMOVE_FUNCTION_BODY += MQTT_ReceiveLoop
REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_c_handleIncomingPublish
REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_c_handleKeepAlive
-#REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_c_sendMessageVector
-#REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_c_sendBuffer
+REMOVE_FUNCTION_BODY += updateContextWithConnectProps
+REMOVE_FUNCTION_BODY += MQTT_ValidateWillProperties
+REMOVE_FUNCTION_BODY += MQTT_DeserializeConnAck
+REMOVE_FUNCTION_BODY += serializeConnectFixedHeader
# The loop below is unwound once more than the timeout. The loop below uses
# the user passed in timeout to break the loop.
@@ -72,7 +74,7 @@ UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendBuffer.0:$(MAX_NETWORK_SEND_TR
# The loops are unwound 5 times because these functions divides a size_t
# variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_getRemainingLength.0:5
# This loop will run for the maximum number of publishes pending
# acknowledgements plus one. This value is set in
@@ -89,7 +91,9 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/get_time_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
+PROJECT_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
EXPENSIVE = true
diff --git a/test/cbmc/proofs/MQTT_DeserializeAck/MQTT_DeserializeAck_harness.c b/test/cbmc/proofs/MQTT_DeserializeAck/MQTT_DeserializeAck_harness.c
index 09dd26ff3..62c79bbf6 100644
--- a/test/cbmc/proofs/MQTT_DeserializeAck/MQTT_DeserializeAck_harness.c
+++ b/test/cbmc/proofs/MQTT_DeserializeAck/MQTT_DeserializeAck_harness.c
@@ -29,20 +29,59 @@
#include "core_mqtt.h"
#include "mqtt_cbmc_state.h"
+MQTTStatus_t __CPROVER_file_local_core_mqtt_serializer_c_deserializeConnackProperties( MQTTConnectionProperties_t * pConnackProperties,
+ uint32_t length,
+ uint8_t * pIndex,
+ MQTTPropBuilder_t * pPropBuffer )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
+MQTTStatus_t __CPROVER_file_local_core_mqtt_serializer_c_deserializeSubUnsubAckProperties( MQTTPropBuilder_t * propBuffer,
+ uint8_t * pIndex,
+ size_t * pSubackPropertyLength,
+ uint32_t remainingLength )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
+MQTTStatus_t __CPROVER_file_local_core_mqtt_serializer_c_decodePubAckProperties( MQTTPropBuilder_t * propBuffer,
+ uint8_t * pIndex,
+ uint32_t remainingLength )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
void harness()
{
MQTTPacketInfo_t * pIncomingPacket;
uint16_t * pPacketId;
bool * pSessionPresent;
+ MQTTReasonCodeInfo_t * pReasonCode;
+ MQTTPropBuilder_t * pPropertyBuilder;
+ MQTTConnectionProperties_t * pConnectProperties;
pIncomingPacket = allocateMqttPacketInfo( NULL );
__CPROVER_assume( isValidMqttPacketInfo( pIncomingPacket ) );
/* These are allocated for coverage of a NULL input. */
pPacketId = malloc( sizeof( uint16_t ) );
- pSessionPresent = malloc( sizeof( bool ) );
+ pReasonCode = malloc( sizeof( MQTTReasonCodeInfo_t ) );
+
+ pPropertyBuilder = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( pPropertyBuilder ) );
+
+ pConnectProperties = malloc( sizeof( MQTTConnectionProperties_t ) );
MQTT_DeserializeAck( pIncomingPacket,
pPacketId,
- pSessionPresent );
+ pReasonCode,
+ pPropertyBuilder,
+ pConnectProperties );
}
diff --git a/test/cbmc/proofs/MQTT_DeserializeAck/Makefile b/test/cbmc/proofs/MQTT_DeserializeAck/Makefile
index 70a447247..b43d6e986 100644
--- a/test/cbmc/proofs/MQTT_DeserializeAck/Makefile
+++ b/test/cbmc/proofs/MQTT_DeserializeAck/Makefile
@@ -26,15 +26,20 @@ PROOF_UID=MQTT_DeserializeAck
# The maximum remaining length is bounded for MQTT_DeserializeAck() in order to
# place a limit on the number of iterations in deserializing a SUBACK. Please
# see REMAINING_LENGTH_MAX in libraries\standard\mqtt\cbmc\sources\mqtt_cbmc_state.c.
-REMAINING_LENGTH_MAX=5
+REMAINING_LENGTH_MAX=6
DEFINES += -DREMAINING_LENGTH_MAX=$(REMAINING_LENGTH_MAX)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
+REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_serializer_c_deserializeConnackProperties
+REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_serializer_c_deserializeSubUnsubAckProperties
+REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_serializer_c_decodePubAckProperties
+
+UNWINDSET += decodeVariableLength.0:5
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_readSubackStatus.0:$(REMAINING_LENGTH_MAX)
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_DeserializeDisconnect/MQTT_DeserializeDisconnect_harness.c b/test/cbmc/proofs/MQTT_DeserializeDisconnect/MQTT_DeserializeDisconnect_harness.c
new file mode 100644
index 000000000..ddc7fa0ec
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_DeserializeDisconnect/MQTT_DeserializeDisconnect_harness.c
@@ -0,0 +1,63 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+#include "private/core_mqtt_serializer_private.h"
+
+MQTTStatus_t __CPROVER_file_local_core_mqtt_serializer_c_validateIncomingDisconnectProperties( uint8_t * pIndex,
+ uint32_t propertyLength )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
+void harness()
+{
+ MQTTReasonCodeInfo_t * pDisconnectInfo;
+ MQTTPacketInfo_t * pIncomingPacket;
+ MQTTPropBuilder_t * propBuffer;
+ uint32_t maxPacketSize;
+
+ pIncomingPacket = allocateMqttPacketInfo( NULL );
+ __CPROVER_assume( isValidMqttPacketInfo( pIncomingPacket ) );
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ __CPROVER_assume( maxPacketSize > 0 );
+ __CPROVER_assume( maxPacketSize < MQTT_MAX_PACKET_SIZE );
+
+ pDisconnectInfo = malloc( sizeof( MQTTReasonCodeInfo_t ) );
+
+ /* This function grabs the topic name, the topic name length, the
+ * the payload, and the payload length. */
+ MQTT_DeserializeDisconnect( pIncomingPacket, maxPacketSize, pDisconnectInfo, propBuffer );
+}
diff --git a/test/cbmc/proofs/MQTT_DeserializeDisconnect/Makefile b/test/cbmc/proofs/MQTT_DeserializeDisconnect/Makefile
new file mode 100644
index 000000000..767cfc968
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_DeserializeDisconnect/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTT_DeserializeDisconnect_harness
+PROOF_UID=MQTT_DeserializeDisconnect
+
+DEFINES +=
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_serializer_c_validateIncomingDisconnectProperties
+
+UNWINDSET += decodeVariableLength.0:5
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_DeserializeDisconnect/README.md b/test/cbmc/proofs/MQTT_DeserializeDisconnect/README.md
new file mode 100644
index 000000000..9090c5fea
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_DeserializeDisconnect/README.md
@@ -0,0 +1,10 @@
+MQTT_DeserializeDisconnect proof
+==============
+
+This directory contains a memory safety proof for MQTT_DeserializeDisconnect.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-proof.txt b/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-viewer.json b/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-viewer.json
new file mode 100644
index 000000000..ee604784e
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_DeserializeDisconnect/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTT_DeserializeDisconnect",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/MQTT_DeserializePublish/MQTT_DeserializePublish_harness.c b/test/cbmc/proofs/MQTT_DeserializePublish/MQTT_DeserializePublish_harness.c
index 531f8044d..f3ca9021d 100644
--- a/test/cbmc/proofs/MQTT_DeserializePublish/MQTT_DeserializePublish_harness.c
+++ b/test/cbmc/proofs/MQTT_DeserializePublish/MQTT_DeserializePublish_harness.c
@@ -28,13 +28,44 @@
*/
#include "core_mqtt.h"
+#include "private/core_mqtt_serializer_private.h"
#include "mqtt_cbmc_state.h"
+MQTTStatus_t __CPROVER_file_local_core_mqtt_serializer_c_deserializePublishProperties( MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * propBuffer,
+ uint8_t * pIndex,
+ uint16_t topicAliasMax,
+ uint32_t remainingLength )
+{
+ MQTTStatus_t status;
+ size_t propertyLength = 0U;
+ uint8_t * pLocalIndex = pIndex;
+ uint32_t remainingLengthForProperties;
+
+ remainingLengthForProperties = remainingLength;
+ remainingLengthForProperties -= pPublishInfo->topicNameLength + sizeof( uint16_t );
+ remainingLengthForProperties -= ( pPublishInfo->qos > 0 ) ? sizeof( uint16_t ) : 0;
+
+ status = decodeVariableLength( pLocalIndex, remainingLengthForProperties, &propertyLength );
+ pPublishInfo->propertyLength = propertyLength;
+
+ if( ( status == MQTTSuccess ) &&
+ ( propertyLength > remainingLengthForProperties - variableLengthEncodedSizeForProof( propertyLength ) ) )
+ {
+ status = MQTTBadResponse;
+ }
+
+ return status;
+}
+
void harness()
{
MQTTPacketInfo_t * pIncomingPacket;
MQTTPublishInfo_t * pPublishInfo;
+ MQTTPropBuilder_t * propBuffer;
+ uint16_t topicAliasMax;
uint16_t * pPacketId;
+ uint32_t maxPacketSize;
pIncomingPacket = allocateMqttPacketInfo( NULL );
__CPROVER_assume( isValidMqttPacketInfo( pIncomingPacket ) );
@@ -42,9 +73,15 @@ void harness()
pPublishInfo = allocateMqttPublishInfo( NULL );
__CPROVER_assume( isValidMqttPublishInfo( pPublishInfo ) );
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
pPacketId = malloc( sizeof( uint16_t ) );
+ __CPROVER_assume( maxPacketSize > 0 );
+ __CPROVER_assume( maxPacketSize < MQTT_MAX_PACKET_SIZE );
+
/* This function grabs the topic name, the topic name length, the
* the payload, and the payload length. */
- MQTT_DeserializePublish( pIncomingPacket, pPacketId, pPublishInfo );
+ MQTT_DeserializePublish( pIncomingPacket, pPacketId, pPublishInfo, propBuffer, maxPacketSize, topicAliasMax );
}
diff --git a/test/cbmc/proofs/MQTT_DeserializePublish/Makefile b/test/cbmc/proofs/MQTT_DeserializePublish/Makefile
index 1c346d61c..1021b3fbf 100644
--- a/test/cbmc/proofs/MQTT_DeserializePublish/Makefile
+++ b/test/cbmc/proofs/MQTT_DeserializePublish/Makefile
@@ -26,11 +26,15 @@ PROOF_UID=MQTT_DeserializePublish
DEFINES +=
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
-UNWINDSET +=
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += __CPROVER_file_local_core_mqtt_serializer_c_deserializePublishProperties
+
+UNWINDSET += decodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_Disconnect/MQTT_Disconnect_harness.c b/test/cbmc/proofs/MQTT_Disconnect/MQTT_Disconnect_harness.c
index 95fb4eee1..de66bcf1c 100644
--- a/test/cbmc/proofs/MQTT_Disconnect/MQTT_Disconnect_harness.c
+++ b/test/cbmc/proofs/MQTT_Disconnect/MQTT_Disconnect_harness.c
@@ -28,15 +28,56 @@
*/
#include "core_mqtt.h"
#include "mqtt_cbmc_state.h"
+#include "core_mqtt_config_defaults.h"
+
+/**
+ * @brief Implement a get time function to return timeout after certain
+ * iterations have been made in the code. This ensures that we do not hit
+ * unwinding error in CBMC. In real life scenarios, the send function will
+ * not just keep accepting 1 byte at a time for a long time since it just
+ * gets added to the TCP buffer.
+ *
+ * @return The global system time.
+ */
+static uint32_t ulGetTimeFunction( void )
+{
+ static uint32_t systemTime = 0;
+
+ if( systemTime >= MAX_NETWORK_SEND_TRIES )
+ {
+ systemTime = systemTime + MQTT_SEND_TIMEOUT_MS + 1;
+ }
+ else
+ {
+ systemTime = systemTime + 1;
+ }
+
+ return systemTime;
+}
+
+MQTTStatus_t MQTT_ValidateDisconnectProperties( uint32_t connectSessionExpiry,
+ const MQTTPropBuilder_t * pPropertyBuilder )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
void harness()
{
MQTTContext_t * pContext;
+ MQTTPropBuilder_t * propBuffer;
+ MQTTSuccessFailReasonCode_t * reasonCode = malloc( sizeof( MQTTSuccessFailReasonCode_t ) );
pContext = allocateMqttContext( NULL );
__CPROVER_assume( isValidMqttContext( pContext ) );
__CPROVER_assume( pContext != NULL );
__CPROVER_assume( pContext->networkBuffer.pBuffer != NULL );
- MQTT_Disconnect( pContext );
+ pContext->getTime = ulGetTimeFunction;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ MQTT_Disconnect( pContext, propBuffer, reasonCode );
}
diff --git a/test/cbmc/proofs/MQTT_Disconnect/Makefile b/test/cbmc/proofs/MQTT_Disconnect/Makefile
index 351ad5b60..b60029590 100644
--- a/test/cbmc/proofs/MQTT_Disconnect/Makefile
+++ b/test/cbmc/proofs/MQTT_Disconnect/Makefile
@@ -26,16 +26,18 @@ PROOF_UID=MQTT_Disconnect
# Please see test/cbmc/stubs/network_interface_subs.c for
# more information on MAX_NETWORK_SEND_TRIES.
MAX_NETWORK_SEND_TRIES=3
+
+DISCONNECT_PACKET_VECTORS = 4
+
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
-# Unlike recvExact, sendBuffer is not bounded by the timeout. The loop in
-# sendBuffer will continue until all the bytes are sent or a network error
-# occurs. Please see NetworkInterfaceReceiveStub in
-# libraries\standard\mqtt\cbmc\stubs\network_interface_stubs.c for more
-# information.
-UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendBuffer.0:$(MAX_NETWORK_SEND_TRIES)
+REMOVE_FUNCTION_BODY += MQTT_ValidateDisconnectProperties
+
+UNWINDSET += encodeVariableLength.0:5
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.0:${DISCONNECT_PACKET_VECTORS}
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.1:${DISCONNECT_PACKET_VECTORS}
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.2:${DISCONNECT_PACKET_VECTORS}
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
@@ -44,6 +46,7 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/get_time_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_GetBytesInMQTTVec/MQTT_GetBytesInMQTTVec_harness.c b/test/cbmc/proofs/MQTT_GetBytesInMQTTVec/MQTT_GetBytesInMQTTVec_harness.c
index 08d3203aa..83a1bafad 100644
--- a/test/cbmc/proofs/MQTT_GetBytesInMQTTVec/MQTT_GetBytesInMQTTVec_harness.c
+++ b/test/cbmc/proofs/MQTT_GetBytesInMQTTVec/MQTT_GetBytesInMQTTVec_harness.c
@@ -36,5 +36,5 @@ void harness()
mqttVec = allocateMqttVec( NULL );
- memoryRequired = MQTT_GetBytesInMQTTVec( mqttVec );
+ MQTTStatus_t status = MQTT_GetBytesInMQTTVec( mqttVec, &memoryRequired );
}
diff --git a/test/cbmc/proofs/MQTT_GetNextPropertyType/MQTT_GetNextPropertyType_harness.c b/test/cbmc/proofs/MQTT_GetNextPropertyType/MQTT_GetNextPropertyType_harness.c
new file mode 100644
index 000000000..5541b8949
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_GetNextPropertyType/MQTT_GetNextPropertyType_harness.c
@@ -0,0 +1,52 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "core_mqtt_serializer.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * propertyId;
+ size_t * currentIndex = malloc( sizeof( size_t ) );
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ propertyId = malloc( sizeof( uint8_t ) );
+
+ MQTT_GetNextPropertyType( propBuffer, currentIndex, propertyId );
+}
diff --git a/test/cbmc/proofs/MQTT_GetNextPropertyType/Makefile b/test/cbmc/proofs/MQTT_GetNextPropertyType/Makefile
new file mode 100644
index 000000000..325aafac4
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_GetNextPropertyType/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTT_GetNextPropertyType_harness
+PROOF_UID=MQTT_GetNextPropertyType
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET +=
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_GetNextPropertyType/README.md b/test/cbmc/proofs/MQTT_GetNextPropertyType/README.md
new file mode 100644
index 000000000..d7d85433d
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_GetNextPropertyType/README.md
@@ -0,0 +1,10 @@
+MQTT_GetNextPropertyType proof
+==============
+
+This directory contains a memory safety proof for MQTT_GetNextPropertyType.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-proof.txt b/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-viewer.json b/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-viewer.json
new file mode 100644
index 000000000..356ff47a3
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_GetNextPropertyType/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTT_GetNextPropertyType",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTT_GetSubAckStatusCodes/Makefile b/test/cbmc/proofs/MQTT_GetSubAckStatusCodes/Makefile
index 940c086d6..c7a8de97c 100644
--- a/test/cbmc/proofs/MQTT_GetSubAckStatusCodes/Makefile
+++ b/test/cbmc/proofs/MQTT_GetSubAckStatusCodes/Makefile
@@ -27,10 +27,13 @@ DEFINES +=
INCLUDES +=
REMOVE_FUNCTION_BODY +=
-UNWINDSET +=
+
+UNWINDSET += decodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_Init/Makefile b/test/cbmc/proofs/MQTT_Init/Makefile
index 1f70af1ec..98dcd0d10 100644
--- a/test/cbmc/proofs/MQTT_Init/Makefile
+++ b/test/cbmc/proofs/MQTT_Init/Makefile
@@ -32,5 +32,6 @@ UNWINDSET +=
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_MatchTopic/README.md b/test/cbmc/proofs/MQTT_MatchTopic/README.md
new file mode 100644
index 000000000..8ca4c04df
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_MatchTopic/README.md
@@ -0,0 +1,10 @@
+MQTT_MatchTopic proof
+==============
+
+This directory contains a memory safety proof for MQTT_MatchTopic.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_ProcessLoop/MQTT_ProcessLoop_harness.c b/test/cbmc/proofs/MQTT_ProcessLoop/MQTT_ProcessLoop_harness.c
index 792221b54..0703f0fa0 100644
--- a/test/cbmc/proofs/MQTT_ProcessLoop/MQTT_ProcessLoop_harness.c
+++ b/test/cbmc/proofs/MQTT_ProcessLoop/MQTT_ProcessLoop_harness.c
@@ -31,13 +31,76 @@
MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- bool * pSessionPresent )
+ MQTTReasonCodeInfo_t * pReasonCode,
+ MQTTPropBuilder_t * propBuffer,
+ MQTTConnectionProperties_t * pConnectProperties )
{
MQTTStatus_t result;
return result;
}
+MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+ uint16_t * pPacketId,
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * propBuffer,
+ uint32_t maxPacketSize,
+ uint16_t topicAliasMax )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTPropBuilder_t * pDisconnectProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTFixedBuffer_t * pFixedBuffer )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_DeserializeDisconnect( const MQTTPacketInfo_t * pPacket,
+ uint32_t maxPacketSize,
+ MQTTReasonCodeInfo_t * pDisconnectInfo,
+ MQTTPropBuilder_t * propBuffer )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_GetDisconnectPacketSize( const MQTTPropBuilder_t * pDisconnectProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ MQTTSuccessFailReasonCode_t * pReasonCode )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
+ const size_t * pIndex,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ static counter = 5;
+
+ counter--;
+
+ if( counter == 0 )
+ {
+ return MQTTBadResponse;
+ }
+
+ MQTTStatus_t result;
+
+ return result;
+}
+
void harness()
{
MQTTContext_t * pContext;
diff --git a/test/cbmc/proofs/MQTT_ProcessLoop/Makefile b/test/cbmc/proofs/MQTT_ProcessLoop/Makefile
index b1f72d17d..67cc7f2a1 100644
--- a/test/cbmc/proofs/MQTT_ProcessLoop/Makefile
+++ b/test/cbmc/proofs/MQTT_ProcessLoop/Makefile
@@ -47,6 +47,8 @@ INCLUDES +=
# These functions have their memory saftey proven in other harnesses.
REMOVE_FUNCTION_BODY += MQTT_Ping
REMOVE_FUNCTION_BODY += MQTT_DeserializeAck
+REMOVE_FUNCTION_BODY += MQTT_DeserializePublish
+REMOVE_FUNCTION_BODY += MQTT_DeserializeDisconnect
REMOVE_FUNCTION_BODY += MQTT_SerializeAck
REMOVE_FUNCTION_BODY += memmove # Use stub
@@ -67,6 +69,7 @@ UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_processRemainingLength.
# test/cbmc/include/core_mqtt_config.h.
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_addRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_findInRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_receiveSingleIteration.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
@@ -76,6 +79,7 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memmove.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
EXPENSIVE = true
diff --git a/test/cbmc/proofs/MQTT_Publish/MQTT_Publish_harness.c b/test/cbmc/proofs/MQTT_Publish/MQTT_Publish_harness.c
index cc48aac25..4503c2f04 100644
--- a/test/cbmc/proofs/MQTT_Publish/MQTT_Publish_harness.c
+++ b/test/cbmc/proofs/MQTT_Publish/MQTT_Publish_harness.c
@@ -54,11 +54,20 @@ static uint32_t ulGetTimeFunction( void )
return systemTime;
}
+MQTTStatus_t MQTT_ValidatePublishProperties( uint16_t serverTopicAliasMax,
+ const MQTTPropBuilder_t * propBuilder,
+ uint16_t * topicAlias )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
void harness()
{
MQTTContext_t * pContext;
MQTTPublishInfo_t * pPublishInfo;
+ MQTTPropBuilder_t * propBuffer;
uint16_t packetId;
pContext = allocateMqttContext( NULL );
@@ -72,5 +81,8 @@ void harness()
pPublishInfo = allocateMqttPublishInfo( NULL );
__CPROVER_assume( isValidMqttPublishInfo( pPublishInfo ) );
- MQTT_Publish( pContext, pPublishInfo, packetId );
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ MQTT_Publish( pContext, pPublishInfo, packetId, propBuffer );
}
diff --git a/test/cbmc/proofs/MQTT_Publish/Makefile b/test/cbmc/proofs/MQTT_Publish/Makefile
index e506cdf65..5fc8d77b5 100644
--- a/test/cbmc/proofs/MQTT_Publish/Makefile
+++ b/test/cbmc/proofs/MQTT_Publish/Makefile
@@ -29,21 +29,22 @@ MAX_NETWORK_SEND_TRIES=3
# Please see test/cbmc/include/core_mqtt_config.h for more
# information.
MQTT_STATE_ARRAY_MAX_COUNT=11
-PUBLISH_PACKET_VECTORS = 5
+PUBLISH_PACKET_VECTORS = 7
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
+REMOVE_FUNCTION_BODY += MQTT_ValidatePublishProperties
REMOVE_FUNCTION_BODY +=
# These loops will run for the maximum number of publishes pending acknowledgement.
# This is set in test/cbmc/include/core_mqtt_config.h.
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_addRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_findInRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
+UNWINDSET += encodeVariableLength.0:5
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.0:${PUBLISH_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.1:${PUBLISH_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.2:${PUBLISH_PACKET_VECTORS}
@@ -55,6 +56,7 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/get_time_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_ReceiveLoop/MQTT_ReceiveLoop_harness.c b/test/cbmc/proofs/MQTT_ReceiveLoop/MQTT_ReceiveLoop_harness.c
index 688114903..97e75665f 100644
--- a/test/cbmc/proofs/MQTT_ReceiveLoop/MQTT_ReceiveLoop_harness.c
+++ b/test/cbmc/proofs/MQTT_ReceiveLoop/MQTT_ReceiveLoop_harness.c
@@ -31,13 +31,76 @@
MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
uint16_t * pPacketId,
- bool * pSessionPresent )
+ MQTTReasonCodeInfo_t * pReasonCode,
+ MQTTPropBuilder_t * propBuffer,
+ MQTTConnectionProperties_t * pConnectProperties )
{
MQTTStatus_t result;
return result;
}
+MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
+ uint16_t * pPacketId,
+ MQTTPublishInfo_t * pPublishInfo,
+ MQTTPropBuilder_t * propBuffer,
+ uint32_t maxPacketSize,
+ uint16_t topicAliasMax )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_SerializeDisconnect( const MQTTPropBuilder_t * pDisconnectProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ const MQTTFixedBuffer_t * pFixedBuffer )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_DeserializeDisconnect( const MQTTPacketInfo_t * pPacket,
+ uint32_t maxPacketSize,
+ MQTTReasonCodeInfo_t * pDisconnectInfo,
+ MQTTPropBuilder_t * propBuffer )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_GetDisconnectPacketSize( const MQTTPropBuilder_t * pDisconnectProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ MQTTSuccessFailReasonCode_t * pReasonCode )
+{
+ MQTTStatus_t result;
+
+ return result;
+}
+
+MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
+ const size_t * pIndex,
+ MQTTPacketInfo_t * pIncomingPacket )
+{
+ static counter = 5;
+
+ counter--;
+
+ if( counter == 0 )
+ {
+ return MQTTBadResponse;
+ }
+
+ MQTTStatus_t result;
+
+ return result;
+}
+
void harness()
{
MQTTContext_t * pContext;
diff --git a/test/cbmc/proofs/MQTT_ReceiveLoop/Makefile b/test/cbmc/proofs/MQTT_ReceiveLoop/Makefile
index 0a161df95..adf4a8342 100644
--- a/test/cbmc/proofs/MQTT_ReceiveLoop/Makefile
+++ b/test/cbmc/proofs/MQTT_ReceiveLoop/Makefile
@@ -21,6 +21,10 @@ MAX_NETWORK_SEND_TRIES=3
# Please see test/cbmc/include/core_mqtt_config.h for more
# information.
MQTT_STATE_ARRAY_MAX_COUNT=11
+
+# Maximum number of vecotrs to be sent in the call to process loop.
+MAX_SEND_VECTORS=10
+
DEFINES += -DMQTT_RECEIVE_TIMEOUT=$(MQTT_RECEIVE_TIMEOUT)
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
DEFINES += -DMAX_NETWORK_RECV_TRIES=$(MAX_NETWORK_RECV_TRIES)
@@ -29,6 +33,10 @@ INCLUDES +=
# These functions have their memory saftey proven in other harnesses.
REMOVE_FUNCTION_BODY += MQTT_DeserializeAck
REMOVE_FUNCTION_BODY += MQTT_SerializeAck
+REMOVE_FUNCTION_BODY += MQTT_SerializeDisconnect
+REMOVE_FUNCTION_BODY += MQTT_DeserializePublish
+REMOVE_FUNCTION_BODY += MQTT_DeserializeDisconnect
+REMOVE_FUNCTION_BODY += MQTT_ProcessIncomingPacketTypeAndLength # So that we can control when the loop exits.
REMOVE_FUNCTION_BODY += memmove # Use stub
# The loops below are unwound once more than the exclusive timeout bound.
@@ -40,14 +48,15 @@ UNWINDSET += __CPROVER_file_local_core_mqtt_c_recvExact.0:$(MAX_NETWORK_RECV_TRI
# libraries\standard\mqtt\cbmc\stubs\network_interface_stubs.c for more
# information.
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendBuffer.0:$(MAX_NETWORK_SEND_TRIES)
-# The getRemainingLength loop is unwound 5 times because getRemainingLength()
-# divides a size_t variable by 128 until it reaches zero to stop the loop.
-# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_processRemainingLength.0:5
# These loops will run for the maximum number of publishes pending acknowledgement.
# This is set in test/cbmc/include/core_mqtt_config.h.
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_addRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
UNWINDSET += __CPROVER_file_local_core_mqtt_state_c_findInRecord.0:$(MQTT_STATE_ARRAY_MAX_COUNT)
+# This loop will run only once.
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_receiveSingleIteration.0:5
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.0:${MAX_SEND_VECTORS}
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.1:${MAX_SEND_VECTORS}
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.2:${MAX_SEND_VECTORS}
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
@@ -57,6 +66,7 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memmove.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
EXPENSIVE = true
diff --git a/test/cbmc/proofs/MQTT_SerializeAck/MQTT_SerializeAck_harness.c b/test/cbmc/proofs/MQTT_SerializeAck/MQTT_SerializeAck_harness.c
index 23c22c7bc..d19b5c237 100644
--- a/test/cbmc/proofs/MQTT_SerializeAck/MQTT_SerializeAck_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeAck/MQTT_SerializeAck_harness.c
@@ -34,9 +34,18 @@ void harness()
MQTTFixedBuffer_t * pFixedBuffer;
uint8_t packetType;
uint16_t packetId;
+ MQTTSuccessFailReasonCode_t ReasonCode;
+ MQTTPropBuilder_t * pAckProperties;
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
- MQTT_SerializeAck( pFixedBuffer, packetType, packetId );
+ pAckProperties = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( pAckProperties ) );
+
+ MQTT_SerializeAck( pFixedBuffer,
+ packetType,
+ packetId,
+ pAckProperties,
+ &ReasonCode );
}
diff --git a/test/cbmc/proofs/MQTT_SerializeAck/Makefile b/test/cbmc/proofs/MQTT_SerializeAck/Makefile
index 4d2e6b652..647351f83 100644
--- a/test/cbmc/proofs/MQTT_SerializeAck/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializeAck/Makefile
@@ -32,5 +32,6 @@ UNWINDSET +=
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializeConnect/MQTT_SerializeConnect_harness.c b/test/cbmc/proofs/MQTT_SerializeConnect/MQTT_SerializeConnect_harness.c
index fea4e8bb1..3419af8d6 100644
--- a/test/cbmc/proofs/MQTT_SerializeConnect/MQTT_SerializeConnect_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeConnect/MQTT_SerializeConnect_harness.c
@@ -29,22 +29,35 @@
#include "core_mqtt.h"
#include "mqtt_cbmc_state.h"
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH ( 25U )
+
+uint8_t * encodeString( uint8_t * pDestination,
+ const char * pSource,
+ uint16_t sourceLength )
+{
+ size_t index;
+
+ __CPROVER_assert( pDestination != NULL, "Destination must not be NULL." );
+
+ /* We just return this as this reduces the time taken to run the proof. */
+ return &pDestination[ 2U ];
+}
+
void harness()
{
MQTTConnectInfo_t * pConnectInfo;
MQTTPublishInfo_t * pWillInfo;
- size_t remainingLength;
+ uint32_t remainingLength;
MQTTFixedBuffer_t * pFixedBuffer;
- size_t packetSize;
+ uint32_t packetSize;
MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t * pConnectProperties;
+ MQTTPropBuilder_t * pWillProperties;
pConnectInfo = allocateMqttConnectInfo( NULL );
-
- /* Avoid a malloc(0U) which causes dereference errors */
- if( ( pConnectInfo != NULL ) && ( pConnectInfo->clientIdentifierLength == 0U ) )
- {
- pConnectInfo->pClientIdentifier = NULL;
- }
+ __CPROVER_assume( isValidMqttConnectInfo( pConnectInfo ) );
pWillInfo = allocateMqttPublishInfo( NULL );
__CPROVER_assume( isValidMqttPublishInfo( pWillInfo ) );
@@ -52,6 +65,28 @@ void harness()
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
+ pConnectProperties = allocateMqttPropBuilder( NULL );
+
+ if( pConnectProperties != NULL )
+ {
+ __CPROVER_assume( pConnectProperties->bufferLength >= 0 );
+ __CPROVER_assume( pConnectProperties->bufferLength <= MAX_PROPERTY_LENGTH );
+ __CPROVER_assume( pConnectProperties->currentIndex >= 0 );
+ __CPROVER_assume( pConnectProperties->currentIndex < pConnectProperties->bufferLength );
+ __CPROVER_assume( pConnectProperties->fieldSet >= 0 );
+ }
+
+ pWillProperties = allocateMqttPropBuilder( NULL );
+
+ if( pWillProperties != NULL )
+ {
+ __CPROVER_assume( pWillProperties->bufferLength >= 0 );
+ __CPROVER_assume( pWillProperties->bufferLength <= MAX_PROPERTY_LENGTH );
+ __CPROVER_assume( pWillProperties->currentIndex >= 0 );
+ __CPROVER_assume( pWillProperties->currentIndex < pWillProperties->bufferLength );
+ __CPROVER_assume( pWillProperties->fieldSet >= 0 );
+ }
+
/* Before calling MQTT_SerializeConnect() it is up to the application to make
* sure that the information in MQTTConnectInfo_t and MQTTPublishInfo_t can
* fit into the MQTTFixedBuffer_t. It is a violation of the API to call
@@ -65,6 +100,8 @@ void harness()
* to recalculate the packetSize. */
status = MQTT_GetConnectPacketSize( pConnectInfo,
pWillInfo,
+ pConnectProperties,
+ pWillProperties,
&remainingLength,
&packetSize );
}
@@ -73,6 +110,11 @@ void harness()
{
/* For coverage, it is expected that a NULL pConnectInfo will reach this
* function. */
- MQTT_SerializeConnect( pConnectInfo, pWillInfo, remainingLength, pFixedBuffer );
+ MQTT_SerializeConnect( pConnectInfo,
+ pWillInfo,
+ pConnectProperties,
+ pWillProperties,
+ remainingLength,
+ pFixedBuffer );
}
}
diff --git a/test/cbmc/proofs/MQTT_SerializeConnect/Makefile b/test/cbmc/proofs/MQTT_SerializeConnect/Makefile
index 8f7483609..9ac7d58a8 100644
--- a/test/cbmc/proofs/MQTT_SerializeConnect/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializeConnect/Makefile
@@ -23,21 +23,22 @@ HARNESS_ENTRY=harness
HARNESS_FILE=MQTT_SerializeConnect_harness
PROOF_UID=MQTT_SerializeConnect
-DEFINES +=
INCLUDES +=
# This function does not coincide with the call graph of MQTT_Serialize, but is
# found by CBMC during processing in logs/MQTT_Connect_harness3.txt. We remove
# the function body to improve coverage accuracy.
REMOVE_FUNCTION_BODY += MQTT_GetIncomingPacketTypeAndLength
+REMOVE_FUNCTION_BODY += encodeString
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializeDisconnect/MQTT_SerializeDisconnect_harness.c b/test/cbmc/proofs/MQTT_SerializeDisconnect/MQTT_SerializeDisconnect_harness.c
index 80a4f544f..63b9284d7 100644
--- a/test/cbmc/proofs/MQTT_SerializeDisconnect/MQTT_SerializeDisconnect_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeDisconnect/MQTT_SerializeDisconnect_harness.c
@@ -32,9 +32,34 @@
void harness()
{
MQTTFixedBuffer_t * pFixedBuffer;
+ MQTTPropBuilder_t * pDisconnectProperties;
+ MQTTSuccessFailReasonCode_t * reasonCode = NULL;
+ MQTTStatus_t status;
+ uint32_t remainingLength;
+ uint32_t packetSize;
+ uint32_t maxPacketSize;
+
+ pDisconnectProperties = allocateMqttPropBuilder( NULL );
+
+ if( pDisconnectProperties != NULL )
+ {
+ __CPROVER_assume( pDisconnectProperties->currentIndex >= 0 );
+ __CPROVER_assume( pDisconnectProperties->currentIndex < pDisconnectProperties->bufferLength );
+ __CPROVER_assume( pDisconnectProperties->fieldSet >= 0 );
+ }
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
- MQTT_SerializeDisconnect( pFixedBuffer );
+ if( nondet_bool() )
+ {
+ reasonCode = malloc( sizeof( MQTTSuccessFailReasonCode_t ) );
+ }
+
+ status = MQTT_GetDisconnectPacketSize( pDisconnectProperties, &remainingLength, &packetSize, maxPacketSize, reasonCode );
+
+ if( status == MQTTSuccess )
+ {
+ MQTT_SerializeDisconnect( pDisconnectProperties, reasonCode, remainingLength, pFixedBuffer );
+ }
}
diff --git a/test/cbmc/proofs/MQTT_SerializeDisconnect/Makefile b/test/cbmc/proofs/MQTT_SerializeDisconnect/Makefile
index 013b72c11..0b9c88ebc 100644
--- a/test/cbmc/proofs/MQTT_SerializeDisconnect/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializeDisconnect/Makefile
@@ -23,14 +23,17 @@ HARNESS_ENTRY=harness
HARNESS_FILE=MQTT_SerializeDisconnect_harness
PROOF_UID=MQTT_SerializeDisconnect
-DEFINES +=
+MAX_TOPIC_NAME_FILTER_LENGTH=10
+
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
-UNWINDSET +=
+REMOVE_FUNCTION_BODY += MQTT_GetIncomingPacketTypeAndLength
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializeMQTTVec/MQTT_SerializeMQTTVec_harness.c b/test/cbmc/proofs/MQTT_SerializeMQTTVec/MQTT_SerializeMQTTVec_harness.c
index 2d283cbbd..4f29d367e 100644
--- a/test/cbmc/proofs/MQTT_SerializeMQTTVec/MQTT_SerializeMQTTVec_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeMQTTVec/MQTT_SerializeMQTTVec_harness.c
@@ -37,7 +37,7 @@ void harness()
mqttVec = allocateMqttVec( NULL );
- memoryRequired = MQTT_GetBytesInMQTTVec( mqttVec );
+ MQTT_GetBytesInMQTTVec( mqttVec, &memoryRequired );
/* It is a part of the API contract that #MQTT_SerializeMQTTVec will be called with
* a memory buffer of size output by #MQTT_GetBytesInMQTTVec function and the
diff --git a/test/cbmc/proofs/MQTT_SerializePublish/MQTT_SerializePublish_harness.c b/test/cbmc/proofs/MQTT_SerializePublish/MQTT_SerializePublish_harness.c
index 1acafaae7..16eb1b9c8 100644
--- a/test/cbmc/proofs/MQTT_SerializePublish/MQTT_SerializePublish_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializePublish/MQTT_SerializePublish_harness.c
@@ -33,10 +33,12 @@ void harness()
{
MQTTPublishInfo_t * pPublishInfo;
uint16_t packetId;
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
const MQTTFixedBuffer_t * pFixedBuffer;
+ MQTTPropBuilder_t * pPublishProperties;
MQTTStatus_t status = MQTTSuccess;
+ uint32_t maxPacketSize;
pPublishInfo = allocateMqttPublishInfo( NULL );
__CPROVER_assume( isValidMqttPublishInfo( pPublishInfo ) );
@@ -44,6 +46,15 @@ void harness()
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
+ pPublishProperties = allocateMqttPropBuilder( NULL );
+
+ if( pPublishProperties != NULL )
+ {
+ __CPROVER_assume( pPublishProperties->currentIndex >= 0 );
+ __CPROVER_assume( pPublishProperties->currentIndex < pPublishProperties->bufferLength );
+ __CPROVER_assume( pPublishProperties->fieldSet >= 0 );
+ }
+
/* Before calling MQTT_SerializePublish() it is up to the application to
* make sure that the information in MQTTPublishInfo_t can fit into the
* MQTTFixedBuffer_t. It is a violation of the API to call
@@ -55,7 +66,7 @@ void harness()
* is used normally by the application to verify the size of its
* MQTTFixedBuffer_t. MQTT_SerializeConnect() will use the remainingLength
* to recalculate the packetSize. */
- status = MQTT_GetPublishPacketSize( pPublishInfo, &remainingLength, &packetSize );
+ status = MQTT_GetPublishPacketSize( pPublishInfo, pPublishProperties, &remainingLength, &packetSize, maxPacketSize );
}
if( status == MQTTSuccess )
@@ -63,6 +74,7 @@ void harness()
/* For coverage it is expected that a NULL pPublishInfo could
* reach this function. */
MQTT_SerializePublish( pPublishInfo,
+ pPublishProperties,
packetId,
remainingLength,
pFixedBuffer );
diff --git a/test/cbmc/proofs/MQTT_SerializePublish/Makefile b/test/cbmc/proofs/MQTT_SerializePublish/Makefile
index 2cd7e5bdd..9c173dd4a 100644
--- a/test/cbmc/proofs/MQTT_SerializePublish/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializePublish/Makefile
@@ -23,17 +23,20 @@ HARNESS_ENTRY=harness
HARNESS_FILE=MQTT_SerializePublish_harness
PROOF_UID=MQTT_SerializePublish
-DEFINES +=
+MAX_TOPIC_NAME_FILTER_LENGTH=10
+
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
INCLUDES +=
REMOVE_FUNCTION_BODY +=
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializePublishHeader/MQTT_SerializePublishHeader_harness.c b/test/cbmc/proofs/MQTT_SerializePublishHeader/MQTT_SerializePublishHeader_harness.c
index 9a74e9626..6323a20f7 100644
--- a/test/cbmc/proofs/MQTT_SerializePublishHeader/MQTT_SerializePublishHeader_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializePublishHeader/MQTT_SerializePublishHeader_harness.c
@@ -33,11 +33,13 @@ void harness()
{
MQTTPublishInfo_t * pPublishInfo;
uint16_t packetId;
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
MQTTFixedBuffer_t * pFixedBuffer;
size_t * pHeaderSize;
+ MQTTPropBuilder_t * pPublishProperties;
MQTTStatus_t status = MQTTSuccess;
+ uint32_t maxPacketSize;
pPublishInfo = allocateMqttPublishInfo( NULL );
__CPROVER_assume( isValidMqttPublishInfo( pPublishInfo ) );
@@ -45,6 +47,15 @@ void harness()
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
+ pPublishProperties = allocateMqttPropBuilder( NULL );
+
+ if( pPublishProperties != NULL )
+ {
+ __CPROVER_assume( pPublishProperties->currentIndex >= 0 );
+ __CPROVER_assume( pPublishProperties->currentIndex < pPublishProperties->bufferLength );
+ __CPROVER_assume( pPublishProperties->fieldSet >= 0 );
+ }
+
/* Allocate space for a returned header size to get coverage of a possibly
* NULL input. */
pHeaderSize = malloc( sizeof( size_t ) );
@@ -61,8 +72,10 @@ void harness()
* MQTTFixedBuffer_t. MQTT_SerializeConnect() will use the remainingLength
* to recalculate the packetSize. */
status = MQTT_GetPublishPacketSize( pPublishInfo,
+ pPublishProperties,
&remainingLength,
- &packetSize );
+ &packetSize,
+ maxPacketSize );
}
if( status == MQTTSuccess )
@@ -70,6 +83,7 @@ void harness()
/* For coverage it is expected that a NULL pPublishInfo could
* reach this function. */
MQTT_SerializePublishHeader( pPublishInfo,
+ pPublishProperties,
packetId,
remainingLength,
pFixedBuffer,
diff --git a/test/cbmc/proofs/MQTT_SerializePublishHeader/Makefile b/test/cbmc/proofs/MQTT_SerializePublishHeader/Makefile
index 6d9f2d9f0..b19725057 100644
--- a/test/cbmc/proofs/MQTT_SerializePublishHeader/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializePublishHeader/Makefile
@@ -22,18 +22,20 @@
HARNESS_ENTRY=harness
HARNESS_FILE=MQTT_SerializePublishHeader_harness
PROOF_UID=MQTT_SerializePublishHeader
+MAX_TOPIC_NAME_FILTER_LENGTH=10
-DEFINES +=
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
INCLUDES +=
REMOVE_FUNCTION_BODY +=
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializeSubscribe/MQTT_SerializeSubscribe_harness.c b/test/cbmc/proofs/MQTT_SerializeSubscribe/MQTT_SerializeSubscribe_harness.c
index 19267433d..9c00e7f54 100644
--- a/test/cbmc/proofs/MQTT_SerializeSubscribe/MQTT_SerializeSubscribe_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeSubscribe/MQTT_SerializeSubscribe_harness.c
@@ -33,11 +33,13 @@ void harness()
{
MQTTSubscribeInfo_t * pSubscriptionList;
size_t subscriptionCount;
- size_t remainingLength;
+ uint32_t remainingLength;
uint16_t packetId;
- size_t packetSize;
+ uint32_t packetSize;
MQTTFixedBuffer_t * pFixedBuffer;
MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t * pSubscribeProperties;
+ uint32_t maxPacketSize;
/* Please see the default bound description on SUBSCRIPTION_COUNT_MAX in
* mqtt_cbmc_state.c for more information. */
@@ -49,6 +51,15 @@ void harness()
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
+ pSubscribeProperties = allocateMqttPropBuilder( NULL );
+
+ if( pSubscribeProperties != NULL )
+ {
+ __CPROVER_assume( pSubscribeProperties->currentIndex >= 0 );
+ __CPROVER_assume( pSubscribeProperties->currentIndex < pSubscribeProperties->bufferLength );
+ __CPROVER_assume( pSubscribeProperties->fieldSet >= 0 );
+ }
+
/* Before calling MQTT_SerializeSubscribe() it is up to the application to
* make sure that the information in the list of MQTTSubscribeInfo_t can fit
* into the MQTTFixedBuffer_t. It is a violation of the API to call
@@ -62,8 +73,10 @@ void harness()
* to recalculate the packetSize. */
status = MQTT_GetSubscribePacketSize( pSubscriptionList,
subscriptionCount,
+ pSubscribeProperties,
&remainingLength,
- &packetSize );
+ &packetSize,
+ maxPacketSize );
}
if( status == MQTTSuccess )
@@ -72,6 +85,7 @@ void harness()
* reach this function. */
MQTT_SerializeSubscribe( pSubscriptionList,
subscriptionCount,
+ pSubscribeProperties,
packetId,
remainingLength,
pFixedBuffer );
diff --git a/test/cbmc/proofs/MQTT_SerializeSubscribe/Makefile b/test/cbmc/proofs/MQTT_SerializeSubscribe/Makefile
index 541179ea8..2c026c351 100644
--- a/test/cbmc/proofs/MQTT_SerializeSubscribe/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializeSubscribe/Makefile
@@ -27,6 +27,9 @@ PROOF_UID=MQTT_SerializeSubscribe
# mqtt_cbmc_state.c for more information on this bound. This is set to 2
# currently to have the proof run quickly.
SUBSCRIPTION_COUNT_MAX=2
+MAX_TOPIC_NAME_FILTER_LENGTH=10
+
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
DEFINES += -DSUBSCRIPTION_COUNT_MAX=$(SUBSCRIPTION_COUNT_MAX)
INCLUDES +=
@@ -34,14 +37,16 @@ REMOVE_FUNCTION_BODY +=
UNWINDSET += allocateMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += isValidMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_calculateSubscriptionPacketSize.0:$(SUBSCRIPTION_COUNT_MAX)
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_validateSubscriptionSerializeParams.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += MQTT_SerializeSubscribe.0:$(SUBSCRIPTION_COUNT_MAX)
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SerializeUnsubscribe/MQTT_SerializeUnsubscribe_harness.c b/test/cbmc/proofs/MQTT_SerializeUnsubscribe/MQTT_SerializeUnsubscribe_harness.c
index 39980e551..3cf653b56 100644
--- a/test/cbmc/proofs/MQTT_SerializeUnsubscribe/MQTT_SerializeUnsubscribe_harness.c
+++ b/test/cbmc/proofs/MQTT_SerializeUnsubscribe/MQTT_SerializeUnsubscribe_harness.c
@@ -33,12 +33,14 @@ void harness()
{
MQTTSubscribeInfo_t * pSubscriptionList;
size_t subscriptionCount;
- size_t remainingLength;
+ uint32_t remainingLength;
uint16_t packetId;
+ MQTTPropBuilder_t * pUnsubscribeProperties;
+ uint32_t maxPacketSize;
/* This variable is not used but is needed for MQTT_GetUnsubscribePacketSize()
* to verify the pSubscriptionList. */
- size_t packetSize;
+ uint32_t packetSize;
MQTTFixedBuffer_t * pFixedBuffer;
MQTTStatus_t status = MQTTSuccess;
@@ -52,6 +54,15 @@ void harness()
pFixedBuffer = allocateMqttFixedBuffer( NULL );
__CPROVER_assume( isValidMqttFixedBuffer( pFixedBuffer ) );
+ pUnsubscribeProperties = allocateMqttPropBuilder( NULL );
+
+ if( pUnsubscribeProperties != NULL )
+ {
+ __CPROVER_assume( pUnsubscribeProperties->currentIndex >= 0 );
+ __CPROVER_assume( pUnsubscribeProperties->currentIndex < pUnsubscribeProperties->bufferLength );
+ __CPROVER_assume( pUnsubscribeProperties->fieldSet >= 0 );
+ }
+
/* Before calling MQTT_SerializeUnsubscribe() it is up to the application to
* make sure that the information in the list of MQTTSubscribeInfo_t can fit
* into the MQTTFixedBuffer_t. It is a violation of the API to call
@@ -65,8 +76,10 @@ void harness()
* to recalculate the packetSize. */
status = MQTT_GetUnsubscribePacketSize( pSubscriptionList,
subscriptionCount,
+ pUnsubscribeProperties,
&remainingLength,
- &packetSize );
+ &packetSize,
+ maxPacketSize );
}
if( status == MQTTSuccess )
@@ -75,6 +88,7 @@ void harness()
* reach this function. */
MQTT_SerializeUnsubscribe( pSubscriptionList,
subscriptionCount,
+ pUnsubscribeProperties,
packetId,
remainingLength,
pFixedBuffer );
diff --git a/test/cbmc/proofs/MQTT_SerializeUnsubscribe/Makefile b/test/cbmc/proofs/MQTT_SerializeUnsubscribe/Makefile
index d68fe649e..3eafa3845 100644
--- a/test/cbmc/proofs/MQTT_SerializeUnsubscribe/Makefile
+++ b/test/cbmc/proofs/MQTT_SerializeUnsubscribe/Makefile
@@ -27,6 +27,9 @@ PROOF_UID=MQTT_SerializeUnsubscribe
# mqtt_cbmc_state.c for more information on this bound. This is set to 2
# currently to have the proof run quickly.
SUBSCRIPTION_COUNT_MAX=2
+MAX_TOPIC_NAME_FILTER_LENGTH=10
+
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
DEFINES += -DSUBSCRIPTION_COUNT_MAX=$(SUBSCRIPTION_COUNT_MAX)
INCLUDES +=
@@ -34,14 +37,17 @@ REMOVE_FUNCTION_BODY +=
UNWINDSET += allocateMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += isValidMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_calculateSubscriptionPacketSize.0:$(SUBSCRIPTION_COUNT_MAX)
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_validateSubscriptionSerializeParams.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += MQTT_SerializeUnsubscribe.0:$(SUBSCRIPTION_COUNT_MAX)
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+# PROJECT_SOURCES += $(SRCDIR)/source/
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SkipNextProperty/MQTT_SkipNextProperty_harness.c b/test/cbmc/proofs/MQTT_SkipNextProperty/MQTT_SkipNextProperty_harness.c
new file mode 100644
index 000000000..f41cbdb85
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_SkipNextProperty/MQTT_SkipNextProperty_harness.c
@@ -0,0 +1,48 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_Disconnect_harness.c
+ * @brief Implements the proof harness for MQTT_Disconnect function.
+ */
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ size_t currentIndex;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ if( propBuffer != NULL )
+ {
+ __CPROVER_assume( propBuffer->currentIndex >= 0 );
+ __CPROVER_assume( propBuffer->currentIndex < propBuffer->bufferLength );
+ __CPROVER_assume( propBuffer->fieldSet >= 0 );
+ }
+
+ MQTT_SkipNextProperty( propBuffer, ¤tIndex );
+}
diff --git a/test/cbmc/proofs/MQTT_SkipNextProperty/Makefile b/test/cbmc/proofs/MQTT_SkipNextProperty/Makefile
new file mode 100644
index 000000000..06503d353
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_SkipNextProperty/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=MQTT_SkipNextProperty_harness
+PROOF_UID=MQTT_SkipNextProperty
+
+
+DEFINES +=
+INCLUDES +=
+
+REMOVE_FUNCTION_BODY +=
+
+UNWINDSET += decodeVariableLength.0:5
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_prop_deserializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_SkipNextProperty/README.md b/test/cbmc/proofs/MQTT_SkipNextProperty/README.md
new file mode 100644
index 000000000..b4311b8a0
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_SkipNextProperty/README.md
@@ -0,0 +1,10 @@
+MQTT_SkipNextProperty proof
+==============
+
+This directory contains a memory safety proof for MQTT_SkipNextProperty.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-proof.txt b/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-viewer.json b/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-viewer.json
new file mode 100644
index 000000000..6ae444d99
--- /dev/null
+++ b/test/cbmc/proofs/MQTT_SkipNextProperty/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "MQTT_SkipNextProperty",
+ "proof-root": "test/cbmc/proofs"
+}
diff --git a/test/cbmc/proofs/MQTT_Subscribe/MQTT_Subscribe_harness.c b/test/cbmc/proofs/MQTT_Subscribe/MQTT_Subscribe_harness.c
index abcc2be14..70f68201d 100644
--- a/test/cbmc/proofs/MQTT_Subscribe/MQTT_Subscribe_harness.c
+++ b/test/cbmc/proofs/MQTT_Subscribe/MQTT_Subscribe_harness.c
@@ -55,10 +55,19 @@ static uint32_t ulGetTimeFunction( void )
return systemTime;
}
+MQTTStatus_t MQTT_ValidateSubscribeProperties( bool isSubscriptionIdAvailable,
+ const MQTTPropBuilder_t * propBuilder )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
void harness()
{
MQTTContext_t * pContext;
MQTTSubscribeInfo_t * pSubscriptionList;
+ MQTTPropBuilder_t * propBuffer;
size_t subscriptionCount;
uint16_t packetId;
@@ -77,5 +86,8 @@ void harness()
pSubscriptionList = allocateMqttSubscriptionList( NULL, 1U );
__CPROVER_assume( isValidMqttSubscriptionList( pSubscriptionList, 1U ) );
- MQTT_Subscribe( pContext, pSubscriptionList, subscriptionCount, packetId );
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ MQTT_Subscribe( pContext, pSubscriptionList, subscriptionCount, packetId, propBuffer );
}
diff --git a/test/cbmc/proofs/MQTT_Subscribe/Makefile b/test/cbmc/proofs/MQTT_Subscribe/Makefile
index e8d064094..e89db4387 100644
--- a/test/cbmc/proofs/MQTT_Subscribe/Makefile
+++ b/test/cbmc/proofs/MQTT_Subscribe/Makefile
@@ -30,29 +30,35 @@ MAX_NETWORK_SEND_TRIES=3
# mqtt_cbmc_state.c for more information on this bound. This is set to 2
# currently to have the proof run quickly.
SUBSCRIPTION_COUNT_MAX=2
-SUBSCRIBE_PACKET_VECTORS = 5
+SUBSCRIBE_PACKET_VECTORS = 7
+MAX_TOPIC_NAME_FILTER_LENGTH=10
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
DEFINES += -DSUBSCRIPTION_COUNT_MAX=$(SUBSCRIPTION_COUNT_MAX)
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
+REMOVE_FUNCTION_BODY += MQTT_ValidateSubscribeProperties
# Unlike recvExact, sendBuffer is not bounded by the timeout. The loop in
# sendBuffer will continue until all the bytes are sent or a network error
# occurs. Please see NetworkInterfaceReceiveStub in
# libraries\standard\mqtt\cbmc\stubs\network_interface_stubs.c for more
# information.
-UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendBuffer.0:$(MAX_NETWORK_SEND_TRIES)
+UNWINDSET += strncmp.0:$(MAX_TOPIC_NAME_FILTER_LENGTH)
+UNWINDSET += strchr.0:$(MAX_TOPIC_NAME_FILTER_LENGTH)
UNWINDSET += allocateMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_validateSharedSubscriptions.0:$(MAX_TOPIC_NAME_FILTER_LENGTH)
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_calculateSubscriptionPacketSize.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_validateSubscribeUnsubscribeParams.0:$(SUBSCRIPTION_COUNT_MAX)
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_validateSubscribeUnsubscribeParams.1:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.0:${SUBSCRIBE_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.1:${SUBSCRIBE_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.2:${SUBSCRIBE_PACKET_VECTORS}
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
+UNWINDSET += encodeVariableLength.0:5
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendSubscribeWithoutCopy.0:$(MAX_NETWORK_SEND_TRIES)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendSubscribeWithoutCopy.1:$(MAX_NETWORK_SEND_TRIES)
@@ -61,8 +67,10 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/network_interface_stubs.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/get_time_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memchr.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/MQTT_Unsubscribe/MQTT_Unsubscribe_harness.c b/test/cbmc/proofs/MQTT_Unsubscribe/MQTT_Unsubscribe_harness.c
index 9f020b9a5..a7df72a5f 100644
--- a/test/cbmc/proofs/MQTT_Unsubscribe/MQTT_Unsubscribe_harness.c
+++ b/test/cbmc/proofs/MQTT_Unsubscribe/MQTT_Unsubscribe_harness.c
@@ -55,12 +55,20 @@ static uint32_t ulGetTimeFunction( void )
return systemTime;
}
+MQTTStatus_t MQTT_ValidateUnsubscribeProperties( const MQTTPropBuilder_t * pPropertyBuilder )
+{
+ MQTTStatus_t status;
+
+ return status;
+}
+
void harness()
{
MQTTContext_t * pContext;
MQTTSubscribeInfo_t * pSubscriptionList;
size_t subscriptionCount;
uint16_t packetId;
+ MQTTPropBuilder_t * pUnsubscribeProperties;
pContext = allocateMqttContext( NULL );
__CPROVER_assume( isValidMqttContext( pContext ) );
@@ -77,5 +85,14 @@ void harness()
pSubscriptionList = allocateMqttSubscriptionList( NULL, 1U );
__CPROVER_assume( isValidMqttSubscriptionList( pSubscriptionList, 1U ) );
- MQTT_Unsubscribe( pContext, pSubscriptionList, subscriptionCount, packetId );
+ pUnsubscribeProperties = allocateMqttPropBuilder( NULL );
+
+ if( pUnsubscribeProperties != NULL )
+ {
+ __CPROVER_assume( pUnsubscribeProperties->currentIndex >= 0 );
+ __CPROVER_assume( pUnsubscribeProperties->currentIndex < pUnsubscribeProperties->bufferLength );
+ __CPROVER_assume( pUnsubscribeProperties->fieldSet >= 0 );
+ }
+
+ MQTT_Unsubscribe( pContext, pSubscriptionList, subscriptionCount, packetId, pUnsubscribeProperties );
}
diff --git a/test/cbmc/proofs/MQTT_Unsubscribe/Makefile b/test/cbmc/proofs/MQTT_Unsubscribe/Makefile
index e4d4b2aaf..c2f39d7d2 100644
--- a/test/cbmc/proofs/MQTT_Unsubscribe/Makefile
+++ b/test/cbmc/proofs/MQTT_Unsubscribe/Makefile
@@ -30,30 +30,31 @@ MAX_NETWORK_SEND_TRIES=3
# mqtt_cbmc_state.c for more information on this bound. This is set to 2
# currently to have the proof run quickly.
SUBSCRIPTION_COUNT_MAX=2
-UNSUBSCRIBE_PACKET_VECTORS = 5
+UNSUBSCRIBE_PACKET_VECTORS = 7
+MAX_TOPIC_NAME_FILTER_LENGTH=10
DEFINES += -DMAX_NETWORK_SEND_TRIES=$(MAX_NETWORK_SEND_TRIES)
DEFINES += -DSUBSCRIPTION_COUNT_MAX=$(SUBSCRIPTION_COUNT_MAX)
+DEFINES += -DMAX_TOPIC_NAME_FILTER_LENGTH=$(MAX_TOPIC_NAME_FILTER_LENGTH)
INCLUDES +=
-REMOVE_FUNCTION_BODY +=
+REMOVE_FUNCTION_BODY += MQTT_ValidateUnsubscribeProperties
# Unlike recvExact, sendBuffer is not bounded by the timeout. The loop in
# sendBuffer will continue until all the bytes are sent or a network error
# occurs. Please see NetworkInterfaceReceiveStub in
# libraries\standard\mqtt\cbmc\stubs\network_interface_stubs.c for more
# information.
-UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendBuffer.0:$(MAX_NETWORK_SEND_TRIES)
UNWINDSET += allocateMqttSubscriptionList.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_validateSubscribeUnsubscribeParams.0:$(SUBSCRIPTION_COUNT_MAX)
+UNWINDSET += __CPROVER_file_local_core_mqtt_c_validateSubscribeUnsubscribeParams.1:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_calculateSubscriptionPacketSize.0:$(SUBSCRIPTION_COUNT_MAX)
-UNWINDSET += MQTT_SerializeUnsubscribe.0:$(SUBSCRIPTION_COUNT_MAX)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.0:${UNSUBSCRIBE_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.1:${UNSUBSCRIBE_PACKET_VECTORS}
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendMessageVector.2:${UNSUBSCRIBE_PACKET_VECTORS}
-# The encodeRemainingLength loop is unwound 5 times because encodeRemainingLength()
+# The encodeVariableLength loop is unwound 5 times because encodeVariableLength()
# divides a size_t variable by 128 until it reaches zero to stop the loop.
# log128(SIZE_MAX) = 4.571...
-UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_encodeRemainingLength.0:5
+UNWINDSET += encodeVariableLength.0:5
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendUnsubscribeWithoutCopy.0:$(MAX_NETWORK_SEND_TRIES)
UNWINDSET += __CPROVER_file_local_core_mqtt_c_sendUnsubscribeWithoutCopy.1:$(MAX_NETWORK_SEND_TRIES)
@@ -64,6 +65,7 @@ PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/get_time_stub.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/event_callback_stub.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_state.c
include ../Makefile.common
diff --git a/test/cbmc/proofs/deserializeSubUnsubAckProperties/Makefile b/test/cbmc/proofs/deserializeSubUnsubAckProperties/Makefile
new file mode 100644
index 000000000..5b35fd5bb
--- /dev/null
+++ b/test/cbmc/proofs/deserializeSubUnsubAckProperties/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MQTT_INCOMING_PUBLISH_MAX_PROPERTIES=14
+MAX_UTF_8_STRING_LENGTH=10
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=deserializeSubUnsubAckProperties_harness
+PROOF_UID=deserializeSubUnsubAckProperties
+
+DEFINES += -DMAX_UTF_8_STRING_LENGTH=$(MAX_UTF_8_STRING_LENGTH)
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += decodeUserProp
+REMOVE_FUNCTION_BODY += decodeUtf8
+REMOVE_FUNCTION_BODY += decodeUint8t
+REMOVE_FUNCTION_BODY += decodeUint32t
+
+UNWINDSET += encodeVariableLength.0:5
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_deserializeSubUnsubAckProperties.0:$(MQTT_INCOMING_PUBLISH_MAX_PROPERTIES)
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer_private.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/deserializeSubUnsubAckProperties/README.md b/test/cbmc/proofs/deserializeSubUnsubAckProperties/README.md
new file mode 100644
index 000000000..f26badb6f
--- /dev/null
+++ b/test/cbmc/proofs/deserializeSubUnsubAckProperties/README.md
@@ -0,0 +1,10 @@
+deserializeSubUnsubAckProperties proof
+==============
+
+This directory contains a memory safety proof for deserializeSubUnsubAckProperties.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-proof.txt b/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-viewer.json b/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-viewer.json
new file mode 100644
index 000000000..a9eab8631
--- /dev/null
+++ b/test/cbmc/proofs/deserializeSubUnsubAckProperties/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "deserializeSubUnsubAckProperties",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/deserializeSubUnsubAckProperties/deserializeSubUnsubAckProperties_harness.c b/test/cbmc/proofs/deserializeSubUnsubAckProperties/deserializeSubUnsubAckProperties_harness.c
new file mode 100644
index 000000000..9e9145e97
--- /dev/null
+++ b/test/cbmc/proofs/deserializeSubUnsubAckProperties/deserializeSubUnsubAckProperties_harness.c
@@ -0,0 +1,76 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH 25U
+
+/* Here we assume the minimum size of a property can only be for a variable length
+ * integer property, e.g. subscription ID. Those will contain a 1 byte property ID,
+ * and a variable length integer. Due to this the maximum number of properties that
+ * will be in the packet will be MAX_PROPERTY_LENGTH / MIN_LENGTH_OF_SINGLE_PROPERTY.
+ */
+#define MIN_LENGTH_OF_SINGLE_PROPERTY ( 2U )
+
+#ifndef REMAINING_LENGTH_MAX
+ #define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
+#endif
+
+void harness()
+{
+ MQTTPropBuilder_t * propBuffer;
+ uint8_t * packetBytes;
+ size_t propertyLength;
+ uint32_t remainingLength;
+ size_t minRemainingLength;
+
+ propBuffer = allocateMqttPropBuilder( NULL );
+ __CPROVER_assume( isValidMqttPropBuilder( propBuffer ) );
+
+ __CPROVER_assume( propertyLength >= 0 );
+ __CPROVER_assume( propertyLength <= MAX_PROPERTY_LENGTH );
+
+ minRemainingLength = sizeof( uint16_t ) + propertyLength + variableLengthEncodedSizeForProof( propertyLength );
+
+ __CPROVER_assume( remainingLength >= minRemainingLength );
+ __CPROVER_assume( remainingLength < REMAINING_LENGTH_MAX );
+
+ packetBytes = malloc( remainingLength - sizeof( uint16_t ) );
+ __CPROVER_assume( packetBytes != NULL );
+
+ encodeVariableLength( packetBytes, propertyLength );
+
+ __CPROVER_file_local_core_mqtt_serializer_c_deserializeSubUnsubAckProperties( propBuffer,
+ packetBytes,
+ &propertyLength,
+ remainingLength );
+}
diff --git a/test/cbmc/proofs/validateIncomingDisconnectProperties/Makefile b/test/cbmc/proofs/validateIncomingDisconnectProperties/Makefile
new file mode 100644
index 000000000..be68bc2f9
--- /dev/null
+++ b/test/cbmc/proofs/validateIncomingDisconnectProperties/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+MQTT_INCOMING_MAX_PROPERTIES=14
+MAX_UTF_8_STRING_LENGTH=10
+
+HARNESS_ENTRY=harness
+HARNESS_FILE=validateIncomingDisconnectProperties_harness
+PROOF_UID=validateIncomingDisconnectProperties
+
+DEFINES += -DMAX_UTF_8_STRING_LENGTH=$(MAX_UTF_8_STRING_LENGTH)
+INCLUDES +=
+
+# These functions have their memory saftey proven in other harnesses.
+REMOVE_FUNCTION_BODY += decodeUserProp
+REMOVE_FUNCTION_BODY += decodeUtf8
+REMOVE_FUNCTION_BODY += decodeUint8t
+REMOVE_FUNCTION_BODY += decodeUint32t
+
+UNWINDSET += __CPROVER_file_local_core_mqtt_serializer_c_validateIncomingDisconnectProperties.0:$(MQTT_INCOMING_MAX_PROPERTIES)
+
+PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/mqtt_cbmc_state.c
+PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/deserialize_helpers_stubs.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt.c
+PROJECT_SOURCES += $(SRCDIR)/source/core_mqtt_serializer.c
+
+include ../Makefile.common
diff --git a/test/cbmc/proofs/validateIncomingDisconnectProperties/README.md b/test/cbmc/proofs/validateIncomingDisconnectProperties/README.md
new file mode 100644
index 000000000..fb7c499f8
--- /dev/null
+++ b/test/cbmc/proofs/validateIncomingDisconnectProperties/README.md
@@ -0,0 +1,10 @@
+validateIncomingDisconnectProperties proof
+==============
+
+This directory contains a memory safety proof for validateIncomingDisconnectProperties.
+
+To run the proof.
+* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
+ to your path.
+* Run "make".
+* Open html/index.html in a web browser.
diff --git a/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-proof.txt b/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-proof.txt
new file mode 100644
index 000000000..6ed46f125
--- /dev/null
+++ b/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-proof.txt
@@ -0,0 +1 @@
+# This file marks this directory as containing a CBMC proof.
diff --git a/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-viewer.json b/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-viewer.json
new file mode 100644
index 000000000..3b8f0216a
--- /dev/null
+++ b/test/cbmc/proofs/validateIncomingDisconnectProperties/cbmc-viewer.json
@@ -0,0 +1,7 @@
+{ "expected-missing-functions":
+ [
+
+ ],
+ "proof-name": "validateIncomingDisconnectProperties",
+ "proof-root": "test/cbmc"
+}
diff --git a/test/cbmc/proofs/validateIncomingDisconnectProperties/validateIncomingDisconnectProperties_harness.c b/test/cbmc/proofs/validateIncomingDisconnectProperties/validateIncomingDisconnectProperties_harness.c
new file mode 100644
index 000000000..5f27f3ef5
--- /dev/null
+++ b/test/cbmc/proofs/validateIncomingDisconnectProperties/validateIncomingDisconnectProperties_harness.c
@@ -0,0 +1,56 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file MQTT_DeserializePublish_harness.c
+ * @brief Implements the proof harness for MQTT_DeserializePublish function.
+ */
+
+#include "core_mqtt.h"
+#include "mqtt_cbmc_state.h"
+
+/* Here we constraint the length of the properties to 25 bytes.
+ */
+#define MAX_PROPERTY_LENGTH ( 25U )
+
+/* Here we assume the minimum size of a property can only be for a variable length
+ * integer property, e.g. subscription ID. Those will contain a 1 byte property ID,
+ * and a variable length integer. Due to this the maximum number of properties that
+ * will be in the packet will be MAX_PROPERTY_LENGTH / MIN_LENGTH_OF_SINGLE_PROPERTY.
+ */
+#define MIN_LENGTH_OF_SINGLE_PROPERTY ( 2U )
+
+void harness()
+{
+ uint8_t * packetBytes;
+ size_t propertyLength;
+
+ __CPROVER_assume( propertyLength >= 0 );
+ __CPROVER_assume( propertyLength <= MAX_PROPERTY_LENGTH );
+
+ packetBytes = malloc( propertyLength );
+ __CPROVER_assume( packetBytes != NULL );
+
+ __CPROVER_file_local_core_mqtt_serializer_c_validateIncomingDisconnectProperties( packetBytes, propertyLength );
+}
diff --git a/test/cbmc/sources/mqtt_cbmc_state.c b/test/cbmc/sources/mqtt_cbmc_state.c
index 76a0019c2..2b2bad544 100644
--- a/test/cbmc/sources/mqtt_cbmc_state.c
+++ b/test/cbmc/sources/mqtt_cbmc_state.c
@@ -52,6 +52,10 @@
#define REMAINING_LENGTH_MAX CBMC_MAX_OBJECT_SIZE
#endif
+#ifndef MAX_TOPIC_NAME_FILTER_LENGTH
+ #define MAX_TOPIC_NAME_FILTER_LENGTH 10
+#endif
+
/**
* @brief Determines the maximum number of MQTT PUBLISH messages, pending
* acknowledgement at a time, that are supported for incoming and outgoing
@@ -148,9 +152,36 @@ MQTTConnectInfo_t * allocateMqttConnectInfo( MQTTConnectInfo_t * pConnectInfo )
if( pConnectInfo != NULL )
{
- pConnectInfo->pClientIdentifier = malloc( pConnectInfo->clientIdentifierLength );
- pConnectInfo->pUserName = malloc( pConnectInfo->userNameLength );
- pConnectInfo->pPassword = malloc( pConnectInfo->passwordLength );
+ if( pConnectInfo->clientIdentifierLength != 0 )
+ {
+ pConnectInfo->pClientIdentifier = malloc( pConnectInfo->clientIdentifierLength );
+ }
+ else
+ {
+ /* 0 length malloc cannot be handled by the library properly. */
+
+ /* TODO: Fix this in the lib so that it branches on the length field instead
+ * of the string being NULL or non-NULL. */
+ pConnectInfo->pClientIdentifier = NULL;
+ }
+
+ if( pConnectInfo->userNameLength != 0 )
+ {
+ pConnectInfo->pUserName = malloc( pConnectInfo->userNameLength );
+ }
+ else
+ {
+ pConnectInfo->pUserName = NULL;
+ }
+
+ if( pConnectInfo->passwordLength != 0 )
+ {
+ pConnectInfo->pPassword = malloc( pConnectInfo->passwordLength );
+ }
+ else
+ {
+ pConnectInfo->pPassword = NULL;
+ }
}
return pConnectInfo;
@@ -191,6 +222,63 @@ bool isValidMqttFixedBuffer( const MQTTFixedBuffer_t * pFixedBuffer )
return isValid;
}
+MQTTPropBuilder_t * allocateMqttPropBuilder( MQTTPropBuilder_t * pPropBuilder )
+{
+ uint8_t * buffer;
+ size_t length;
+ size_t nonDetDurrentIndex;
+ uint32_t nonDetFieldSet;
+ MQTTStatus_t status;
+
+ if( pPropBuilder == NULL )
+ {
+ pPropBuilder = malloc( sizeof( MQTTPropBuilder_t ) );
+ }
+
+ if( pPropBuilder != NULL )
+ {
+ __CPROVER_assume( length > 0 );
+
+ /* This buffer is used to store packet properties. The property length
+ * is a variable length integer and hence will have a max value of REMAINING_LENGTH_MAX */
+ __CPROVER_assume( length < REMAINING_LENGTH_MAX );
+
+ buffer = malloc( length );
+
+ /* It is a part of the API contract to call MQTTPropertyBuilder_Init before */
+ status = MQTTPropertyBuilder_Init( pPropBuilder, buffer, length );
+
+ __CPROVER_assume( status == MQTTSuccess );
+
+ __CPROVER_assume( nonDetDurrentIndex >= 0 );
+ __CPROVER_assume( nonDetDurrentIndex < length );
+
+ pPropBuilder->currentIndex = nonDetDurrentIndex;
+ pPropBuilder->fieldSet = nonDetFieldSet;
+ }
+
+ if( status != MQTTSuccess )
+ {
+ pPropBuilder = NULL;
+ }
+
+ return pPropBuilder;
+}
+
+bool isValidMqttPropBuilder( const MQTTPropBuilder_t * pPropBuilder )
+{
+ bool isValid = true;
+
+ if( pPropBuilder != NULL )
+ {
+ isValid = isValid && pPropBuilder->currentIndex >= 0;
+ isValid = isValid && pPropBuilder->fieldSet >= 0;
+ isValid = ( pPropBuilder->currentIndex == 0 ) == ( pPropBuilder->fieldSet == 0 );
+ }
+
+ return isValid;
+}
+
MQTTSubscribeInfo_t * allocateMqttSubscriptionList( MQTTSubscribeInfo_t * pSubscriptionList,
size_t subscriptionCount )
{
@@ -203,6 +291,8 @@ MQTTSubscribeInfo_t * allocateMqttSubscriptionList( MQTTSubscribeInfo_t * pSubsc
{
for( int i = 0; i < subscriptionCount; i++ )
{
+ __CPROVER_assume( pSubscriptionList[ i ].topicFilterLength < MAX_TOPIC_NAME_FILTER_LENGTH );
+
pSubscriptionList[ i ].pTopicFilter = malloc( pSubscriptionList[ i ].topicFilterLength );
}
}
@@ -225,6 +315,7 @@ MQTTContext_t * allocateMqttContext( MQTTContext_t * pContext )
MQTTStatus_t status = MQTTSuccess;
MQTTPubAckInfo_t * pOutgoingAckList;
MQTTPubAckInfo_t * pIncomingAckList;
+ MQTTConnectionStatus_t nonDetConnectStatus;
size_t outgoingAckListSize;
size_t incomingAckListSize;
@@ -280,6 +371,10 @@ MQTTContext_t * allocateMqttContext( MQTTContext_t * pContext )
GetCurrentTimeStub,
EventCallbackStub,
pNetworkBuffer );
+
+ /* This is to make sure that the API's are called with all possible
+ * connection status values */
+ pContext->connectStatus = nonDetConnectStatus;
}
/* If the MQTTContext_t initialization failed, then set the context to NULL
@@ -351,3 +446,34 @@ MQTTVec_t * allocateMqttVec( MQTTVec_t * mqttVec )
return mqttVec;
}
+
+size_t variableLengthEncodedSizeForProof( size_t length )
+{
+ size_t encodedSize;
+
+ /* Determine how many bytes are needed to encode length.
+ * The values below are taken from the MQTT 3.1.1 spec. */
+
+ /* 1 byte is needed to encode lengths between 0 and 127. */
+ if( length < 128U )
+ {
+ encodedSize = 1U;
+ }
+ /* 2 bytes are needed to encode lengths between 128 and 16,383. */
+ else if( length < 16384U )
+ {
+ encodedSize = 2U;
+ }
+ /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */
+ else if( length < 2097152U )
+ {
+ encodedSize = 3U;
+ }
+ /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */
+ else
+ {
+ encodedSize = 4U;
+ }
+
+ return encodedSize;
+}
diff --git a/test/cbmc/stubs/deserialize_helpers_stubs.c b/test/cbmc/stubs/deserialize_helpers_stubs.c
new file mode 100644
index 000000000..546902616
--- /dev/null
+++ b/test/cbmc/stubs/deserialize_helpers_stubs.c
@@ -0,0 +1,143 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file event_callback_stub.c
+ * @brief A stub for the event callback.
+ */
+
+#include
+#include "core_mqtt.h"
+
+#ifndef MAX_UTF_8_STRING_LENGTH
+ #define MAX_UTF_8_STRING_LENGTH ( 10U )
+#endif
+
+/* Here we assume all the properties in the packet are user properties all of the same
+ * length. Each user property includes two UTF-8 strings and
+ * their corresponding 2 byte lengths.
+ */
+#define MAX_LENGTH_OF_SINGLE_PROPERTY ( 2 * MAX_UTF_8_STRING_LENGTH + 4 )
+
+static MQTTStatus_t updatePointer( uint32_t * pPropertyLength,
+ uint8_t ** pIndex )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t length = *pPropertyLength;
+
+ uint32_t decrement = ( length < MAX_LENGTH_OF_SINGLE_PROPERTY ) ? length : MAX_LENGTH_OF_SINGLE_PROPERTY;
+
+ *pPropertyLength -= decrement;
+ *pIndex += decrement;
+
+ return status;
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUserProp( const char ** pPropertyKey,
+ uint16_t * pPropertyKeyLen,
+ const char ** pPropertyValue,
+ uint16_t * pPropertyValueLen,
+ uint32_t * pPropertyLength,
+ uint8_t ** pIndex )
+{
+ if( nondet_bool() )
+ {
+ return updatePointer( pPropertyLength, pIndex );
+ }
+ else
+ {
+ return MQTTBadResponse;
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUtf8( const char ** pProperty,
+ uint16_t * pLength,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ if( nondet_bool() )
+ {
+ return updatePointer( pPropertyLength, pIndex );
+ }
+ else
+ {
+ return MQTTBadResponse;
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint16t( uint16_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ if( nondet_bool() )
+ {
+ return updatePointer( pPropertyLength, pIndex );
+ }
+ else
+ {
+ return MQTTBadResponse;
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint32t( uint32_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ if( nondet_bool() )
+ {
+ return updatePointer( pPropertyLength, pIndex );
+ }
+ else
+ {
+ return MQTTBadResponse;
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+MQTTStatus_t decodeUint8t( uint8_t * pProperty,
+ uint32_t * pPropertyLength,
+ bool * pUsed,
+ uint8_t ** pIndex )
+{
+ if( nondet_bool() )
+ {
+ return updatePointer( pPropertyLength, pIndex );
+ }
+ else
+ {
+ return MQTTBadResponse;
+ }
+}
diff --git a/test/cbmc/stubs/event_callback_stub.c b/test/cbmc/stubs/event_callback_stub.c
index 1f29b3fbd..2f67549f6 100644
--- a/test/cbmc/stubs/event_callback_stub.c
+++ b/test/cbmc/stubs/event_callback_stub.c
@@ -30,9 +30,12 @@
#include "core_mqtt.h"
#include "event_callback_stub.h"
-void EventCallbackStub( MQTTContext_t * pContext,
+bool EventCallbackStub( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
- MQTTDeserializedInfo_t * pDeserializedInfo )
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ enum MQTTSuccessFailReasonCode * pReasonCode,
+ struct MqttPropBuilder * pSendPropsBuffer,
+ struct MqttPropBuilder * pGetPropsBuffer )
{
__CPROVER_assert( pContext != NULL,
"EventCallbackStub pContext is not NULL" );
diff --git a/test/cbmc/stubs/memchr.c b/test/cbmc/stubs/memchr.c
new file mode 100644
index 000000000..f1f045be0
--- /dev/null
+++ b/test/cbmc/stubs/memchr.c
@@ -0,0 +1,42 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include
+
+void * memchr( const void * ptr,
+ int ch,
+ size_t count )
+{
+ const unsigned char * buf = ptr;
+ size_t index;
+
+ __CPROVER_assume( index <= count );
+
+ if( index == count )
+ {
+ return NULL;
+ }
+
+ return ( void * ) ( buf + index );
+}
diff --git a/test/cbmc/stubs/network_interface_stubs.c b/test/cbmc/stubs/network_interface_stubs.c
index 826bb9e64..9564fdf99 100644
--- a/test/cbmc/stubs/network_interface_stubs.c
+++ b/test/cbmc/stubs/network_interface_stubs.c
@@ -63,7 +63,7 @@ int32_t NetworkInterfaceReceiveStub( NetworkContext_t * pNetworkContext,
* more than bytesToRecv. */
__CPROVER_assume( bytesOrError <= ( int32_t ) bytesToRecv );
- if( tries < ( MAX_NETWORK_RECV_TRIES - 1 ) )
+ if( tries < ( MAX_NETWORK_RECV_TRIES - 1U ) )
{
tries++;
}
diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt
index 714c945e3..ab6d0ceed 100644
--- a/test/unit-test/CMakeLists.txt
+++ b/test/unit-test/CMakeLists.txt
@@ -10,12 +10,14 @@ set(project_name "core_mqtt")
list(APPEND mock_list
"${MODULE_ROOT_DIR}/source/include/core_mqtt_serializer.h"
"${MODULE_ROOT_DIR}/source/include/core_mqtt_state.h"
+ "${MODULE_ROOT_DIR}/source/include/private/core_mqtt_serializer_private.h"
)
# list the directories your mocks need
list(APPEND mock_include_list
.
${CMAKE_CURRENT_LIST_DIR}/logging
${MQTT_INCLUDE_PUBLIC_DIRS}
+ "${MODULE_ROOT_DIR}/source/include/private"
)
#list the definitions of your mocks to control what to be included
list(APPEND mock_define_list
@@ -42,6 +44,7 @@ list(APPEND real_include_directories
list(APPEND test_include_directories
.
${MQTT_INCLUDE_PUBLIC_DIRS}
+ "${MODULE_ROOT_DIR}/source/include/private"
)
# ============================= (end edit) ===================================
@@ -62,14 +65,16 @@ create_real_library(${real_name}
"${mock_name}"
)
+list(APPEND utest_dep_list
+ ${real_name}
+ )
+
list(APPEND utest_link_list
-l${mock_name}
lib${real_name}.a
)
-list(APPEND utest_dep_list
- ${real_name}
- )
+
set(utest_name "${project_name}_utest")
set(utest_source "${project_name}_utest.c")
@@ -112,3 +117,19 @@ create_test(${utest_name}
"${utest_dep_list}"
"${test_include_directories}"
)
+
+# mqtt_prop_serializer_utest
+set(utest_name "${project_name}_prop_serializer_utest")
+set(utest_source "${project_name}_prop_serializer_utest.c")
+
+set(utest_link_list "")
+list(APPEND utest_link_list
+ lib${real_name}.a
+ )
+
+create_test(${utest_name}
+ ${utest_source}
+ "${utest_link_list}"
+ "${utest_dep_list}"
+ "${test_include_directories}"
+ )
diff --git a/test/unit-test/cmock_build.cmake b/test/unit-test/cmock_build.cmake
index ef7da713d..adb9202f2 100644
--- a/test/unit-test/cmock_build.cmake
+++ b/test/unit-test/cmock_build.cmake
@@ -15,44 +15,44 @@ endmacro()
# Macro utility to add library targets for Unity and CMock to build configuration.
macro( add_cmock_targets )
# Build Configuration for CMock and Unity libraries.
- list( APPEND CMOCK_INCLUDE_DIRS
- "${CMOCK_DIR}/vendor/unity/src/"
- "${CMOCK_DIR}/vendor/unity/extras/fixture/src"
- "${CMOCK_DIR}/vendor/unity/extras/memory/src"
- "${CMOCK_DIR}/src"
+ list(APPEND CMOCK_INCLUDE_DIRS
+ "${CMOCK_DIR}/vendor/unity/src/"
+ "${CMOCK_DIR}/vendor/unity/extras/fixture/src"
+ "${CMOCK_DIR}/vendor/unity/extras/memory/src"
+ "${CMOCK_DIR}/src"
)
add_library(cmock STATIC
- "${CMOCK_DIR}/src/cmock.c"
+ "${CMOCK_DIR}/src/cmock.c"
)
set_target_properties(cmock PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
- POSITION_INDEPENDENT_CODE ON
- COMPILE_FLAGS "-Og"
- )
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
+ POSITION_INDEPENDENT_CODE ON
+ COMPILE_FLAGS "-Og"
+ )
target_include_directories(cmock PUBLIC
- ${CMOCK_DIR}/src
- ${CMOCK_DIR}/vendor/unity/src/
- ${CMOCK_DIR}/examples
- ${CMOCK_INCLUDE_DIRS}
- )
+ ${CMOCK_DIR}/src
+ ${CMOCK_DIR}/vendor/unity/src/
+ ${CMOCK_DIR}/examples
+ ${CMOCK_INCLUDE_DIRS}
+ )
add_library(unity STATIC
- "${CMOCK_DIR}/vendor/unity/src/unity.c"
- "${CMOCK_DIR}/vendor/unity/extras/fixture/src/unity_fixture.c"
- "${CMOCK_DIR}/vendor/unity/extras/memory/src/unity_memory.c"
- )
+ "${CMOCK_DIR}/vendor/unity/src/unity.c"
+ "${CMOCK_DIR}/vendor/unity/extras/fixture/src/unity_fixture.c"
+ "${CMOCK_DIR}/vendor/unity/extras/memory/src/unity_memory.c"
+ )
set_target_properties(unity PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
- POSITION_INDEPENDENT_CODE ON
- )
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
+ POSITION_INDEPENDENT_CODE ON
+ )
target_include_directories(unity PUBLIC
- ${CMOCK_INCLUDE_DIRS}
- )
+ ${CMOCK_INCLUDE_DIRS}
+ )
target_link_libraries(cmock unity)
endmacro()
diff --git a/test/unit-test/core_mqtt_config.h b/test/unit-test/core_mqtt_config.h
index 24b577f57..768eca070 100644
--- a/test/unit-test/core_mqtt_config.h
+++ b/test/unit-test/core_mqtt_config.h
@@ -43,7 +43,7 @@
* 3. Include the header file "logging_stack.h", if logging is enabled for MQTT.
*/
-#include "logging_levels.h"
+#include "../logging/logging_levels.h"
/* Logging configuration for the MQTT library. */
#ifndef LIBRARY_LOG_NAME
@@ -54,7 +54,7 @@
#define LIBRARY_LOG_LEVEL LOG_NONE
#endif
-#include "logging_stack.h"
+#include "../logging/logging_stack.h"
/************ End of logging configuration ****************/
@@ -71,6 +71,6 @@
#define MQTT_SUB_UNSUB_MAX_VECTORS ( 6U )
-#define MQTT_SEND_TIMEOUT_MS ( 20U )
+#define MQTT_SEND_TIMEOUT_MS ( 200U )
#endif /* ifndef CORE_MQTT_CONFIG_H_ */
diff --git a/test/unit-test/core_mqtt_prop_serializer_utest.c b/test/unit-test/core_mqtt_prop_serializer_utest.c
new file mode 100644
index 000000000..f87852754
--- /dev/null
+++ b/test/unit-test/core_mqtt_prop_serializer_utest.c
@@ -0,0 +1,1767 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file core_mqtt_utest.c
+ * @brief Unit tests for functions in core_mqtt.h.
+ */
+#include
+#include
+#include
+
+#include "unity.h"
+
+/* Include paths for public enums, structures, and macros. */
+#include "core_mqtt_config_defaults.h"
+#include "core_mqtt_serializer.h"
+#include "core_mqtt.h"
+#include "core_mqtt_serializer_private.h"
+
+void test_MQTTPropAdd_SubscriptionId_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint32_t subscriptionId;
+ uint8_t OptionalMqttPacketType;
+ MQTTStatus_t status;
+ uint32_t val = 0;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ subscriptionId = 1;
+ status = MQTTPropAdd_SubscriptionId( NULL, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_SUBSCRIPTION_ID_POS );
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ subscriptionId = ~( ( uint32_t ) ( 0UL ) );
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ subscriptionId = 1;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( PropertyBuilder.fieldSet & ( 1 << MQTT_SUBSCRIPTION_ID_POS ), 1 << MQTT_SUBSCRIPTION_ID_POS );
+ TEST_ASSERT_EQUAL( PropertyBuilder.pBuffer[ 0 ], MQTT_SUBSCRIPTION_ID_ID );
+ /* Only one byte required to encode value of 1. */
+ TEST_ASSERT_EQUAL( PropertyBuilder.pBuffer[ 1 ], 1 );
+ TEST_ASSERT_EQUAL( PropertyBuilder.currentIndex, 2 );
+
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ subscriptionId = 900;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( PropertyBuilder.fieldSet & ( 1 << MQTT_SUBSCRIPTION_ID_POS ), 1 << MQTT_SUBSCRIPTION_ID_POS );
+ TEST_ASSERT_EQUAL( PropertyBuilder.pBuffer[ 0 ], MQTT_SUBSCRIPTION_ID_ID );
+ /* Only two bytes required to encode value of 900. */
+ TEST_ASSERT_EQUAL( 2 + 1, PropertyBuilder.currentIndex );
+ TEST_ASSERT_EQUAL( 128 | 4, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL( 7, PropertyBuilder.pBuffer[ 2 ] );
+ status = decodeVariableLength( &PropertyBuilder.pBuffer[ 1 ], 4, &val );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 900, val );
+
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ subscriptionId = 9000;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( PropertyBuilder.fieldSet & ( 1 << MQTT_SUBSCRIPTION_ID_POS ), 1 << MQTT_SUBSCRIPTION_ID_POS );
+ TEST_ASSERT_EQUAL( PropertyBuilder.pBuffer[ 0 ], MQTT_SUBSCRIPTION_ID_ID );
+ /* Only two bytes required to encode value of 9000. */
+ TEST_ASSERT_EQUAL( 2 + 1, PropertyBuilder.currentIndex );
+ TEST_ASSERT_EQUAL( 128 | 40, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL( 70, PropertyBuilder.pBuffer[ 2 ] );
+ status = decodeVariableLength( &PropertyBuilder.pBuffer[ 1 ], 4, &val );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 9000, val );
+
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ subscriptionId = 2097152U;
+ status = MQTTPropAdd_SubscriptionId( &PropertyBuilder, subscriptionId, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( PropertyBuilder.fieldSet & ( 1 << MQTT_SUBSCRIPTION_ID_POS ), 1 << MQTT_SUBSCRIPTION_ID_POS );
+ TEST_ASSERT_EQUAL( PropertyBuilder.pBuffer[ 0 ], MQTT_SUBSCRIPTION_ID_ID );
+ /* Four bytes required to encode value. */
+ TEST_ASSERT_EQUAL( 4 + 1, PropertyBuilder.currentIndex );
+ TEST_ASSERT_EQUAL( 128 | 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL( 128 | 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 128 | 0, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL( 1, PropertyBuilder.pBuffer[ 4 ] );
+ status = decodeVariableLength( &PropertyBuilder.pBuffer[ 1 ], 4, &val );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2097152U, val );
+}
+
+void test_MQTTPropAdd_UserProp_AdditionOverflow1( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ MQTTUserProperty_t userProperty = { 0 };
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.currentIndex = SIZE_MAX - 2;
+
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTTPropAdd_UserProp_AdditionOverflow2( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ MQTTUserProperty_t userProperty = { 0 };
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.currentIndex = SIZE_MAX - 6;
+
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTTPropAdd_UserProp_AdditionOverflow3( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ MQTTUserProperty_t userProperty = { 0 };
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.currentIndex = SIZE_MAX - 9;
+
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTTPropAdd_UserProp_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ MQTTUserProperty_t userProperty = { 0 };
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_UserProp( NULL, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.bufferLength = 100;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, NULL, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = NULL;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = NULL;
+ userProperty.keyLength = 3;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 0;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 0;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ PropertyBuilder.currentIndex -= 7;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 10;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ userProperty.pKey = "Key";
+ userProperty.pValue = "Value";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 5;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ status = MQTTPropAdd_UserProp( &PropertyBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_USER_PROPERTY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ /* Encoded key length. */
+ TEST_ASSERT_EQUAL( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL( 3, PropertyBuilder.pBuffer[ 2 ] );
+ /* Key itself. */
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Key", 3 ) );
+
+ /* Encoded key length. */
+ TEST_ASSERT_EQUAL( 0, PropertyBuilder.pBuffer[ 6 ] );
+ TEST_ASSERT_EQUAL( 5, PropertyBuilder.pBuffer[ 7 ] );
+ /* Key itself. */
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 8 ], "Value", 5 ) );
+}
+
+void test_MQTTPropAdd_SessionExpiry_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint32_t sessionExpiry = 0;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_SessionExpiry( NULL, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_SESSION_EXPIRY_INTERVAL_POS );
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ sessionExpiry = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_SESSION_EXPIRY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 4 ] );
+
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ sessionExpiry = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTTPropAdd_SessionExpiry( &PropertyBuilder, sessionExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_SESSION_EXPIRY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_ReceiveMax_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint16_t receiveMax = 10;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_ReceiveMax( NULL, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_RECEIVE_MAXIMUM_POS );
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ receiveMax = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_RECEIVE_MAX_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ receiveMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTTPropAdd_ReceiveMax( &PropertyBuilder, receiveMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_RECEIVE_MAX_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_MaxPacketSize_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint32_t maxPacketSize = 10;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_MaxPacketSize( NULL, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_MAX_PACKET_SIZE_POS );
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ maxPacketSize = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_MAX_PACKET_SIZE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 4 ] );
+
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ maxPacketSize = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTTPropAdd_MaxPacketSize( &PropertyBuilder, maxPacketSize, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_MAX_PACKET_SIZE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_MessageExpiry_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint32_t messageExpiry = 10;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_MessageExpiry( NULL, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_MESSAGE_EXPIRY_INTERVAL_POS );
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ messageExpiry = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_MSG_EXPIRY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ messageExpiry = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_MSG_EXPIRY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ messageExpiry = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_MessageExpiry( &PropertyBuilder, messageExpiry, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTTPropAdd_WillDelayInterval_AllInputs( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint32_t willDelayInterVal = 10;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_WillDelayInterval( NULL, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_WILL_DELAY_POS );
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ willDelayInterVal = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_WILL_DELAY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 4 ] );
+
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ willDelayInterVal = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_WILL_DELAY_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ willDelayInterVal = 1000;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_WillDelayInterval( &PropertyBuilder, willDelayInterVal, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTTPropAdd_TopicAliasMax_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint16_t topicAliasMax = 10;
+ uint8_t OptionalMqttPacketType = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_TopicAliasMax( NULL, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_TOPIC_ALIAS_MAX_POS );
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_TOPIC_ALIAS_MAX_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_TOPIC_ALIAS_MAX_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_TOPIC_ALIAS_MAX_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PINGREQ;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PINGRESP;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_TopicAliasMax( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_TopicAlias_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint16_t topicAliasMax = 10;
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_TopicAlias( NULL, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_TOPIC_ALIAS_POS );
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 30;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_TOPIC_ALIAS_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 30, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL( 0xAA, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_TOPIC_ALIAS_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 3, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 232, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ topicAliasMax = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_TopicAlias( &PropertyBuilder, topicAliasMax, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_RequestRespInfo_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ bool requestRespInfo = false;
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_RequestRespInfo( NULL, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_REQUEST_RESPONSE_INFO_POS );
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = false;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REQUEST_RESPONSE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = true;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REQUEST_RESPONSE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 1, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_RequestRespInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_RequestProbInfo_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ bool requestRespInfo = false;
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_RequestProbInfo( NULL, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_REQUEST_PROBLEM_INFO_POS );
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = false;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REQUEST_PROBLEM_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = true;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REQUEST_PROBLEM_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 1, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_RequestProbInfo( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_PayloadFormat_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ bool requestRespInfo = false;
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ MQTTStatus_t status;
+ uint8_t buffer[ 100 ];
+
+ status = MQTTPropAdd_PayloadFormat( NULL, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_PAYLOAD_FORMAT_INDICATOR_POS );
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = 0;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID - 1;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 20;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 0;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = false;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_PAYLOAD_FORMAT_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = true;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ memset( buffer, 0xAA, 100 );
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_PAYLOAD_FORMAT_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 1, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ requestRespInfo = 1000;
+ memset( buffer, 0xAA, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_UNSUBSCRIBE;
+ status = MQTTPropAdd_PayloadFormat( &PropertyBuilder, requestRespInfo, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 3 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0xAA, PropertyBuilder.pBuffer[ 4 ] );
+}
+
+void test_MQTTPropAdd_AuthMethod_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ];
+ MQTTStatus_t status;
+
+ status = MQTTPropAdd_AuthMethod( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ PropertyBuilder.bufferLength = MQTT_REMAINING_LENGTH_INVALID + 50;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_AUTH_METHOD_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_AUTH;
+ status = MQTTPropAdd_AuthMethod( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_AUTH_METHOD_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
+
+void test_MQTTPropAdd_AuthData_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ];
+ MQTTStatus_t status;
+
+ status = MQTTPropAdd_AuthData( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_DATA_POS );
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 100000, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_AUTH_DATA_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_AUTHENTICATION_METHOD_POS );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_AUTH;
+ status = MQTTPropAdd_AuthData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_AUTH_DATA_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
+
+void test_MQTTPropAdd_ReasonString_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ];
+ MQTTStatus_t status;
+
+ status = MQTTPropAdd_ReasonString( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "hello", 65537, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_REASON_STRING_POS );
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBACK;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBACK;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_UNSUBACK;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_DISCONNECT;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REASON_STRING_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_AUTH;
+ status = MQTTPropAdd_ReasonString( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_REASON_STRING_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
+
+void test_MQTTPropAdd_ContentType_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ];
+ MQTTStatus_t status;
+
+ status = MQTTPropAdd_ContentType( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "hello", 65537, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_CONTENT_TYPE_POS );
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_CONTENT_TYPE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_ContentType( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_CONTENT_TYPE_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
+
+void test_MQTTPropAdd_CorrelationData_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ];
+ MQTTStatus_t status;
+
+ status = MQTTPropAdd_CorrelationData( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_CorrelationData( NULL, "hello", 65537, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_CORRELATION_DATA_POS );
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_CORRELATION_DATA_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_CorrelationData( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_CORRELATION_DATA_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
+
+void test_MQTTPropAdd_ResponseTopic_AllCases( void )
+{
+ MQTTPropBuilder_t PropertyBuilder = { 0 };
+ uint8_t OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ uint8_t buffer[ 100 ] = { 0 };
+ MQTTStatus_t status;
+
+ PropertyBuilder.pBuffer = buffer;
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, NULL, 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 0, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "H+llo", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "H#llo", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTTPropAdd_ResponseTopic( NULL, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = NULL;
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet |= ( 1 << MQTT_RESPONSE_TOPIC_POS );
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_SUBSCRIBE;
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ char array[ 65540 ] = { 'A' };
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, array, 65540, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 1;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, NULL );
+ TEST_ASSERT_EQUAL( MQTTNoMemory, status );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_RESPONSE_TOPIC_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+
+ PropertyBuilder.pBuffer = buffer;
+ PropertyBuilder.currentIndex = 0;
+ PropertyBuilder.bufferLength = 100;
+ PropertyBuilder.fieldSet = 0;
+ memset( buffer, 0, 100 );
+ OptionalMqttPacketType = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTTPropAdd_ResponseTopic( &PropertyBuilder, "Hello", 5, &OptionalMqttPacketType );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTT_RESPONSE_TOPIC_ID, PropertyBuilder.pBuffer[ 0 ] );
+ TEST_ASSERT_EQUAL_UINT8( 0, PropertyBuilder.pBuffer[ 1 ] );
+ TEST_ASSERT_EQUAL_UINT8( 5, PropertyBuilder.pBuffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 0, memcmp( &PropertyBuilder.pBuffer[ 3 ], "Hello", 5 ) );
+}
diff --git a/test/unit-test/core_mqtt_serializer_utest.c b/test/unit-test/core_mqtt_serializer_utest.c
index 8b5df8a25..e56c4574b 100644
--- a/test/unit-test/core_mqtt_serializer_utest.c
+++ b/test/unit-test/core_mqtt_serializer_utest.c
@@ -28,9 +28,11 @@
*/
#include
#include
-
+#include
#include "unity.h"
+#include "core_mqtt_serializer_private.h"
+
/* Include paths for public enums, structures, and macros. */
#include "core_mqtt_serializer.h"
@@ -65,48 +67,55 @@ struct NetworkContext
#define TEST_TOPIC_NAME ( "/test/topic" ) /**< @brief An arbitrary topic name. */
#define TEST_TOPIC_NAME_LENGTH ( ( uint16_t ) ( sizeof( TEST_TOPIC_NAME ) - 1 ) ) /**< @brief Length of topic name. */
-
-/**
- * @brief MQTT protocol version 3.1.1.
- */
-#define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U )
-
/**
* @brief Test-defined macro for MQTT username.
*/
-#define MQTT_TEST_USERNAME "username"
-#define MQTT_TEST_USERNAME_LEN ( sizeof( MQTT_TEST_USERNAME ) - 1 )
+#define MQTT_TEST_USERNAME "username"
+#define MQTT_TEST_USERNAME_LEN ( sizeof( MQTT_TEST_USERNAME ) - 1 )
/**
* @brief Test-defined macro for MQTT password.
*/
-#define MQTT_TEST_PASSWORD "password"
-#define MQTT_TEST_PASSWORD_LEN ( sizeof( MQTT_TEST_PASSWORD ) - 1 )
+#define MQTT_TEST_PASSWORD "password"
+#define MQTT_TEST_PASSWORD_LEN ( sizeof( MQTT_TEST_PASSWORD ) - 1 )
/**
* @brief Length of the client identifier.
*/
-#define MQTT_CLIENT_IDENTIFIER_LEN ( sizeof( MQTT_CLIENT_IDENTIFIER ) - 1 )
+#define MQTT_CLIENT_IDENTIFIER_LEN ( sizeof( MQTT_CLIENT_IDENTIFIER ) - 1 )
/**
* @brief Sample payload.
*/
-#define MQTT_SAMPLE_PAYLOAD "Hello World"
-#define MQTT_SAMPLE_PAYLOAD_LEN ( sizeof( MQTT_SAMPLE_PAYLOAD ) - 1 )
+#define MQTT_SAMPLE_PAYLOAD "Hello World"
+#define MQTT_SAMPLE_PAYLOAD_LEN ( sizeof( MQTT_SAMPLE_PAYLOAD ) - 1 )
+
+#define TEST_TOPIC_ALIAS ( 2U )
+#define TEST_MSG_EXPIRY ( 100U )
+
+#define MQTT_TEST_UTF8_STRING ( "test" )
+#define MQTT_TEST_UTF8_STRING_LENGTH ( sizeof( MQTT_TEST_UTF8_STRING ) - 1 )
+#define MQTT_TEST_UINT8 ( 1U )
+#define MQTT_TEST_UINT16 ( 32U )
+#define MQTT_TEST_UINT32 ( 300U )
/* MQTT CONNECT flags. */
-#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */
-#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */
-#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS 1. */
-#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS 2. */
-#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */
-#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */
-#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief User name present. */
+#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */
+#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */
+#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS 1. */
+#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS 2. */
+#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */
+#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */
+#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief User name present. */
+
+/* Default connect properties. */
+#define DEFAULT_RECEIVE_MAX ( 65535U )
+#define DEFAULT_REQUEST_PROBLEM ( 1 )
/**
* @brief The Remaining Length field of MQTT disconnect packets, per MQTT spec.
*/
-#define MQTT_DISCONNECT_REMAINING_LENGTH ( ( uint8_t ) 0 )
+#define MQTT_DISCONNECT_REMAINING_LENGTH ( ( uint8_t ) 0 )
/**
* @brief Set a bit in an 8-bit unsigned integer.
@@ -133,7 +142,7 @@ struct NetworkContext
/**
* @brief Maximum number of bytes in the Remaining Length field is four according
- * to MQTT 3.1.1 spec.
+ * to MQTT 5.0 spec.
*/
#define MQTT_REMAINING_BUFFER_MAX_LENGTH ( 4 )
@@ -152,17 +161,42 @@ struct NetworkContext
*/
#define MQTT_TEST_BUFFER_LENGTH ( 1024 )
-static uint8_t remainingLengthBuffer[ MQTT_REMAINING_BUFFER_MAX_LENGTH ] = { 0 };
+#define UINT16_DECODE( ptr ) \
+ ( uint16_t ) ( ( ( ( uint16_t ) ptr[ 0 ] ) << 8 ) | \
+ ( ( uint16_t ) ptr[ 1 ] ) )
-static uint8_t encodedStringBuffer[ MQTT_TEST_BUFFER_LENGTH ] = { 0 };
+#define UINT32_DECODE( ptr ) \
+ ( uint32_t ) ( ( ( ( uint32_t ) ptr[ 0 ] ) << 24 ) | \
+ ( ( ( uint32_t ) ptr[ 1 ] ) << 16 ) | \
+ ( ( ( uint32_t ) ptr[ 2 ] ) << 8 ) | \
+ ( ( uint32_t ) ptr[ 3 ] ) )
-static uint8_t mqttBuffer[ MQTT_TEST_BUFFER_LENGTH ] = { 0 };
+#define UINT32_BYTE3( x ) ( ( uint8_t ) ( ( x ) >> 24 ) )
+
+#define UINT32_BYTE2( x ) ( ( uint8_t ) ( ( x ) >> 16 ) )
+
+#define UINT32_BYTE1( x ) ( ( uint8_t ) ( ( x ) >> 8 ) )
+
+#define UINT32_BYTE0( x ) ( ( uint8_t ) ( ( x ) & 0x000000FFU ) )
+
+/* Variables common to testcases */
+MQTTConnectionProperties_t properties;
+MQTTUserProperty_t userProperty;
+MQTTPublishInfo_t publishInfo;
+MQTTConnectInfo_t connectInfo;
+MQTTPacketInfo_t packetInfo;
+MQTTStatus_t status;
/* ============================ UNITY FIXTURES ============================ */
/* Called before each test method. */
void setUp( void )
{
+ memset( &properties, 0x0, sizeof( properties ) );
+ memset( &userProperty, 0x0, sizeof( userProperty ) );
+ memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ memset( &packetInfo, 0x0, sizeof( packetInfo ) );
}
/* Called after each test method. */
@@ -186,9 +220,9 @@ int suiteTearDown( int numFailures )
/**
* @brief Mock successful transport receive by reading data from a buffer.
*/
-static int32_t mockReceive( NetworkContext_t * pNetworkContext,
- void * pBuffer,
- size_t bytesToRecv )
+int32_t mockReceive( NetworkContext_t * pNetworkContext,
+ void * pBuffer,
+ size_t bytesToRecv )
{
uint8_t * returnBuffer = ( uint8_t * ) pBuffer;
uint8_t * mockNetwork;
@@ -216,7 +250,7 @@ static int32_t mockReceiveNoData( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
- /* Suppress unused parameter warning. */
+/* Suppress unused parameter warning. */
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToRecv;
@@ -231,7 +265,7 @@ static int32_t mockReceiveFailure( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
- /* Suppress unused parameter warning. */
+/* Suppress unused parameter warning. */
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToRecv;
@@ -264,34 +298,6 @@ static int32_t mockReceiveSucceedThenFail( NetworkContext_t * pNetworkContext,
/* ========================================================================== */
-/**
- * @brief Initialize pNetworkBuffer using static buffer.
- *
- * @param[in] pNetworkBuffer Network buffer provided for the context.
- */
-static void setupNetworkBuffer( MQTTFixedBuffer_t * const pNetworkBuffer )
-{
- pNetworkBuffer->pBuffer = mqttBuffer;
- pNetworkBuffer->size = MQTT_TEST_BUFFER_LENGTH;
-}
-
-/**
- * @brief Initialize pConnectInfo using test-defined macros.
- *
- * @param[in] pConnectInfo MQTT CONNECT packet parameters.
- */
-static void setupConnectInfo( MQTTConnectInfo_t * const pConnectInfo )
-{
- pConnectInfo->cleanSession = true;
- pConnectInfo->pClientIdentifier = MQTT_CLIENT_IDENTIFIER;
- pConnectInfo->clientIdentifierLength = MQTT_CLIENT_IDENTIFIER_LEN;
- pConnectInfo->keepAliveSeconds = 0;
- pConnectInfo->pUserName = MQTT_TEST_USERNAME;
- pConnectInfo->userNameLength = MQTT_TEST_USERNAME_LEN;
- pConnectInfo->pPassword = MQTT_TEST_PASSWORD;
- pConnectInfo->passwordLength = MQTT_TEST_PASSWORD_LEN;
-}
-
/**
* @brief Initialize pPublishInfo using test-defined macros.
*
@@ -310,23 +316,23 @@ static void setupPublishInfo( MQTTPublishInfo_t * pPublishInfo )
/**
* @brief Encode remaining length into pDestination for packet serialization
- * using MQTT v3.1.1 spec.
+ * using MQTT 5.0 spec.
*
* @param[in] pDestination Buffer to write encoded remaining length.
* @param[in] length Actual remaining length.
*/
-static size_t encodeRemainingLength( uint8_t * pDestination,
- size_t length )
+static size_t encodeVariableLengthUT( uint8_t * pDestination,
+ size_t length )
{
uint8_t lengthByte;
uint8_t * pLengthEnd = NULL;
- size_t remainingLength = length;
+ uint32_t remainingLength = length;
TEST_ASSERT_NOT_NULL( pDestination );
pLengthEnd = pDestination;
- /* This algorithm is copied from the MQTT v3.1.1 spec. */
+ /* This algorithm is copied from the MQTT 5.0 spec. */
do
{
lengthByte = ( uint8_t ) ( remainingLength % 128U );
@@ -354,9 +360,49 @@ static size_t encodeRemainingLength( uint8_t * pDestination,
* @param[in] source String to encode.
* @param[in] sourceLength Length of the string to encode.
*/
-static size_t encodeString( uint8_t * pDestination,
- const char * source,
- uint16_t sourceLength )
+static size_t encodeStringUT( uint8_t * pDestination,
+ const char * source,
+ uint16_t sourceLength )
+{
+ uint8_t * pBuffer = NULL;
+
+ /* Typecast const char * typed source buffer to const uint8_t *.
+ * This is to use same type buffers in memcpy. */
+ const uint8_t * pSourceBuffer = ( const uint8_t * ) source;
+
+ TEST_ASSERT_NOT_NULL( pSourceBuffer );
+ TEST_ASSERT_NOT_NULL( pDestination );
+
+ pBuffer = pDestination;
+
+ /* The first byte of a UTF-8 string is the high byte of the string length. */
+ *pBuffer = UINT16_HIGH_BYTE( sourceLength );
+ pBuffer++;
+
+ /* The second byte of a UTF-8 string is the low byte of the string length. */
+ *pBuffer = UINT16_LOW_BYTE( sourceLength );
+ pBuffer++;
+
+ /* Copy the string into pBuffer. */
+ ( void ) memcpy( pBuffer, pSourceBuffer, sourceLength );
+
+ /* Return the pointer to the end of the encoded string. */
+ pBuffer += sourceLength;
+
+ return ( size_t ) ( pBuffer - pDestination );
+}
+
+/**
+ * @brief Encode UTF-8 string and its length into pDestination for
+ * packet serialization.
+ *
+ * @param[in] pDestination Buffer to write encoded string.
+ * @param[in] source String to encode.
+ * @param[in] sourceLength Length of the string to encode.
+ */
+static size_t encodeStringSize( uint8_t * pDestination,
+ const char * source,
+ uint16_t sourceLength )
{
uint8_t * pBuffer = NULL;
@@ -427,135 +473,835 @@ static void checkBufferOverflow( uint8_t * pBuffer,
BUFFER_PADDING_LENGTH );
}
-/* ========================================================================== */
+static uint8_t * initializeDeserialize( MQTTPacketInfo_t * packetInfo,
+ uint8_t * pIndex )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ packetInfo->pRemainingData = pIndexLocal;
+ packetInfo->type = MQTT_PACKET_TYPE_CONNACK;
+ *pIndexLocal = 0x01;
+ pIndexLocal++;
+ *pIndexLocal = 0x00;
+ pIndexLocal++;
+ return pIndexLocal;
+}
-/**
- * @brief Tests that MQTT_GetConnectPacketSize works as intended.
- */
-void test_MQTT_GetConnectPacketSize( void )
+static uint8_t * serializeuint_32( uint8_t * pIndex,
+ uint8_t propertyId )
{
- MQTTConnectInfo_t connectInfo;
- size_t remainingLength = 0;
- size_t packetSize = 0;
- MQTTStatus_t status = MQTTSuccess;
- MQTTPublishInfo_t willInfo = { 0 };
+ uint8_t * pIndexLocal = pIndex;
+
+ *pIndexLocal = propertyId;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ pIndexLocal[ 1 ] = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ pIndexLocal[ 2 ] = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ pIndexLocal[ 3 ] = UINT32_BYTE0( MQTT_TEST_UINT32 );
+ pIndexLocal = &pIndexLocal[ 4 ];
+ return pIndexLocal;
+}
+
+static uint8_t * serializeuint_16( uint8_t * pIndex,
+ uint8_t propertyId )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ *pIndexLocal = propertyId;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ pIndexLocal[ 1 ] = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
+ pIndexLocal = &pIndexLocal[ 2 ];
+ return pIndexLocal;
+}
+
+static uint8_t * serializeuint_8( uint8_t * pIndex,
+ uint8_t propertyId )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ *pIndexLocal = propertyId;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = MQTT_TEST_UINT8;
+ pIndexLocal++;
+ return pIndexLocal;
+}
+static uint8_t * serializeutf_8( uint8_t * pIndex,
+ uint8_t propertyId )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ *pIndexLocal = propertyId;
+ pIndexLocal++;
+ size_t dummy = encodeStringSize( pIndexLocal, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ pIndexLocal = &pIndexLocal[ dummy ];
+ return pIndexLocal;
+}
+
+static uint8_t * serializeutf_8pair( uint8_t * pIndex )
+{
+ uint8_t * pIndexLocal = pIndex;
+
+ *pIndexLocal = MQTT_USER_PROPERTY_ID;
+ pIndexLocal++;
+ size_t dummy = encodeStringSize( pIndexLocal, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ pIndexLocal = &pIndexLocal[ dummy ];
+ dummy = encodeStringSize( pIndexLocal, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ pIndexLocal = &pIndexLocal[ dummy ];
+ return pIndexLocal;
+}
+
+void test_MQTTV5_DeserializeConnackOnlyStatus( void )
+{
+ uint8_t buffer[ 50 ];
+ uint8_t * pIndex = buffer;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ memset( &properties, 0x00, sizeof( properties ) );
+
+ status = MQTT_DeserializeConnAck( NULL, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTT_DeserializeConnAck( &packetInfo, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTT_DeserializeConnAck( NULL, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTT_DeserializeConnAck( &packetInfo, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ packetInfo.pRemainingData = pIndex;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNECT;
+ status = MQTT_DeserializeConnAck( &packetInfo, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* remaining data is NULL. */
+ bool sessionPresent = false;
+ properties.maxPacketSize = 100;
+ packetInfo.pRemainingData = NULL;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 100;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* max packet size is 0. */
+ sessionPresent = false;
+ properties.maxPacketSize = 0;
+ packetInfo.pRemainingData = pIndex;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 100;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Incomplete connack received. */
+ sessionPresent = false;
+ packetInfo.pRemainingData = pIndex;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 2;
+ properties.maxPacketSize = 100;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Reserved bit incorrect. */
+ packetInfo.remainingLength = 3;
+ buffer[ 0 ] = 0x11;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /*
+ * Session Present Bit is set but reason code is not equal to 0;
+ */
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x01;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* 5 + 1 + 2 = 8 */
+ size_t propertyLength = encodeVariableLengthUT( pIndex, 5 );
+ packetInfo.remainingLength = propertyLength + 7;
+ /* Not a valid reason code*/
+ buffer[ 0 ] = 0x00;
+ buffer[ 1 ] = 0x03;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+ /* All the valid response code*/
+ buffer[ 1 ] = 0x80;
+ buffer[ 2 ] = 0;
+ properties.maxPacketSize = 100;
+ packetInfo.remainingLength = 3;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x80;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x81;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x82;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x83;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x80;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x84;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x80;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x85;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x86;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x87;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x88;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x89;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x8A;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x8C;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x88;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x90;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x95;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x97;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x99;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9A;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9A;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9B;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9C;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9D;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ buffer[ 1 ] = 0x9F;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTServerRefused, status );
+
+ /* Exceeds the max packet size set by the client*/
+ properties.maxPacketSize = 2;
+ buffer[ 1 ] = 0x00;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Validate the remaining length*/
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ packetInfo.remainingLength = 7;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 20;
+ pIndex = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ pIndex = &buffer[ 2 ];
+ *pIndex = 0x81;
+ pIndex++;
+ *pIndex = 0x00;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+void test_MQTTV5_DeserializeConnackOnlyuint_32( void )
+{
+ uint8_t buffer[ 200 ] = { 0 };
+ bool session = false;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t * pIndexLocal = initializeDeserialize( &packetInfo, buffer );
+ size_t propertyLength = encodeVariableLengthUT( pIndexLocal, 10 );
+
+ packetInfo.remainingLength = propertyLength + 12;
+ properties.maxPacketSize = 150;
+ pIndexLocal++;
+ pIndexLocal = serializeuint_32( pIndexLocal, MQTT_SESSION_EXPIRY_ID );
+ pIndexLocal = serializeuint_32( pIndexLocal, MQTT_MAX_PACKET_SIZE_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT32, properties.sessionExpiry );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT32, properties.serverMaxPacketSize );
+
+ /* Test with NULL propBuffer. */
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Protocol error to include the same property twice*/
+ packetInfo.remainingLength = 13;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 10 );
+ pIndexLocal++;
+ pIndexLocal = serializeuint_32( pIndexLocal, MQTT_SESSION_EXPIRY_ID );
+ pIndexLocal = serializeuint_32( pIndexLocal, MQTT_SESSION_EXPIRY_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 7;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 4 );
+ pIndexLocal++;
+ *pIndexLocal = MQTT_SESSION_EXPIRY_ID;
+ pIndexLocal++;
+ pIndexLocal = serializeuint_32( pIndexLocal, MQTT_SESSION_EXPIRY_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid id*/
+ packetInfo.remainingLength = 8;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 5 );
+ pIndexLocal++;
+ pIndexLocal = serializeuint_32( pIndexLocal, 0x00 );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Max packet size cannot have a value 0*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 5 );
+ packetInfo.remainingLength = propertyLength + 7;
+ pIndexLocal++;
+ *pIndexLocal = MQTT_MAX_PACKET_SIZE_ID;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = UINT32_BYTE3( 0 );
+ pIndexLocal[ 1 ] = UINT32_BYTE2( 0 );
+ pIndexLocal[ 2 ] = UINT32_BYTE1( 0 );
+ pIndexLocal[ 3 ] = UINT32_BYTE0( 0 );
+ pIndexLocal = &pIndexLocal[ 4 ];
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_MQTTV5_DeserializeConnackOnlyuint_16( void )
+{
+ uint8_t buffer[ 200 ] = { 0 };
+ uint8_t * pIndexLocal = buffer;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+ bool session = false;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ pIndexLocal = &buffer[ 2 ];
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ size_t propertyLength = encodeVariableLengthUT( pIndexLocal, 9 );
+ packetInfo.remainingLength = propertyLength + 11;
+ pIndexLocal++;
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_RECEIVE_MAX_ID );
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_TOPIC_ALIAS_MAX_ID );
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_SERVER_KEEP_ALIVE_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT16, properties.serverReceiveMax );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT16, properties.serverTopicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT16, properties.serverKeepAlive );
+
+ /* Receive Max cannot have a value 0*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 3 );
+ packetInfo.remainingLength = propertyLength + 5;
+ pIndexLocal++;
+ *pIndexLocal = MQTT_RECEIVE_MAX_ID;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( 0 );
+ pIndexLocal[ 1 ] = UINT16_LOW_BYTE( 0 );
+ pIndexLocal = &pIndexLocal[ 2 ];
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Protocol error to include the same property twice*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 6 );
+ packetInfo.remainingLength = propertyLength + 8;
+ pIndexLocal++;
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_RECEIVE_MAX_ID );
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_RECEIVE_MAX_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 5;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 2 );
+ pIndexLocal++;
+ pIndexLocal = serializeuint_16( pIndexLocal, MQTT_RECEIVE_MAX_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_MQTTV5_DeserializeConnackOnlyuint_8( void )
+{
+ uint8_t buffer[ 200 ] = { 0 };
+ uint8_t * pIndexLocal = buffer;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+ bool session = false;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 13;
+ pIndexLocal = &buffer[ 2 ];
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ size_t propertyLength = encodeVariableLengthUT( pIndexLocal, 10 );
+ pIndexLocal++;
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_MAX_QOS_ID );
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_RETAIN_AVAILABLE_ID );
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_WILDCARD_ID );
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_SHARED_SUB_ID );
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_SUB_AVAILABLE_ID );
+
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT8, properties.serverMaxQos );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT8, properties.retainAvailable );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT8, properties.isWildcardAvailable );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT8, properties.isSharedAvailable );
+ TEST_ASSERT_EQUAL_INT( MQTT_TEST_UINT8, properties.isSubscriptionIdAvailable );
+
+ /* Protocol error to have a value other than 0 or 1*/
+ packetInfo.remainingLength = 5;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 2 );
+ pIndexLocal++;
+ *pIndexLocal = MQTT_MAX_QOS_ID;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = 3;
+ pIndexLocal++;
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Protocol error to include the same property twice*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 4 );
+ packetInfo.remainingLength = propertyLength + 6;
+ pIndexLocal++;
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_MAX_QOS_ID );
+ pIndexLocal = serializeuint_8( pIndexLocal, MQTT_MAX_QOS_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 4;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 1 );
+ pIndexLocal++;
+ *pIndexLocal = MQTT_MAX_QOS_ID;
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = 0;
+ pIndexLocal++;
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ uint8_t propertiesArray[] = { MQTT_WILDCARD_ID, MQTT_SUB_AVAILABLE_ID, MQTT_SHARED_SUB_ID, MQTT_RETAIN_AVAILABLE_ID };
+ size_t propIt;
+
+ for( propIt = 0; propIt < sizeof( propertiesArray ); propIt++ )
+ {
+ /* Twice ID. */
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+ session = false;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 13;
+ pIndexLocal = &buffer[ 2 ];
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 10 );
+ pIndexLocal++;
+ pIndexLocal = serializeuint_8( pIndexLocal, propertiesArray[ propIt ] );
+ pIndexLocal = serializeuint_8( pIndexLocal, propertiesArray[ propIt ] );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Illegal ID value. */
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+ session = false;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 13;
+ pIndexLocal = &buffer[ 2 ];
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 10 );
+ pIndexLocal++;
+ pIndexLocal[ 0 ] = propertiesArray[ propIt ];
+ /* Illegal value. */
+ pIndexLocal[ 1 ] = 2;
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ }
+}
+
+void test_MQTTV5_DeserializeConnackOnlyutf_8( void )
+{
+ uint8_t buffer[ 200 ] = { 0 };
+ uint8_t * pIndexLocal = buffer;
+ MQTTPropBuilder_t propBuffer;
+
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+
+ bool session = false;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ pIndexLocal = &buffer[ 2 ];
+ properties.requestResponseInfo = 1;
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ size_t propertyLength = encodeVariableLengthUT( pIndexLocal, 28 );
+ packetInfo.remainingLength = propertyLength + 28 + 2;
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_ASSIGNED_CLIENT_ID );
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_REASON_STRING_ID );
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_RESPONSE_INFO_ID );
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_SERVER_REF_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Protocol error to include the same property twice*/
+ packetInfo.remainingLength = 17;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 14 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_ASSIGNED_CLIENT_ID );
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_ASSIGNED_CLIENT_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 7;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 4 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_ASSIGNED_CLIENT_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 2 );
+ packetInfo.remainingLength = propertyLength + 4;
+ pIndexLocal++;
+ serializeutf_8( pIndexLocal, MQTT_ASSIGNED_CLIENT_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Protocol error to include response information if is is set to false by client*/
+ properties.requestResponseInfo = 0;
+ packetInfo.remainingLength = 10;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 7 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_RESPONSE_INFO_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ packetInfo.remainingLength = 10;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 7 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_AUTH_METHOD_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 7 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8( pIndexLocal, MQTT_AUTH_DATA_ID );
+ status = MQTT_DeserializeConnAck( &packetInfo, &session, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+
+void test_MQTTV5_DeserializeConnackOnlyUserProperty( void )
+{
+ uint8_t buffer[ 70000 ] = { 0 };
+ uint8_t * pIndexLocal = buffer;
+ bool sessionPresent = false;
+
+ buffer[ 0 ] = 0x01;
+ buffer[ 1 ] = 0x00;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 16;
+ pIndexLocal = &buffer[ 2 ];
+ size_t propertyLength = encodeVariableLengthUT( pIndexLocal, 13 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 5;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 2 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 6;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 3 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 8 );
+ packetInfo.remainingLength = propertyLength + 10;
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property length*/
+ packetInfo.remainingLength = 15;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 12 );
+ pIndexLocal++;
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Discard user property*/
+ packetInfo.remainingLength = 65018;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 65013 );
+ pIndexLocal += 3;
+ uint32_t i = 0U;
+
+ for( ; i < 5001; i++ )
+ {
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ }
+
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ packetInfo.remainingLength = 65017;
+ pIndexLocal = &buffer[ 2 ];
+ propertyLength = encodeVariableLengthUT( pIndexLocal, 65012 );
+ pIndexLocal += 3;
+
+ for( ; i < 5001; i++ )
+ {
+ pIndexLocal = serializeutf_8pair( pIndexLocal );
+ }
+
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_MQTTV5_DeserializeConnack_ReasonCodes( void )
+{
+ uint8_t buffer[ 50 ];
+ bool sessionPresent = false;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ memset( &properties, 0x00, sizeof( properties ) );
+ properties.maxPacketSize = 100;
+
+ packetInfo.pRemainingData = buffer;
+ packetInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ packetInfo.remainingLength = 3;
+
+ buffer[ 0 ] = 0x00;
+ buffer[ 2 ] = 0x00;
+
+ buffer[ 1 ] = MQTT_REASON_CONNACK_USE_ANOTHER_SERVER;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+
+ buffer[ 1 ] = MQTT_REASON_CONNACK_SERVER_MOVED;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+
+ buffer[ 1 ] = MQTT_REASON_CONNACK_CONNECTION_RATE_EXCEEDED;
+ status = MQTT_DeserializeConnAck( &packetInfo, &sessionPresent, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+}
+
+void test_MQTTV5_GetConnectPacketSize( void )
+{
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
/* Call MQTT_GetConnectPacketSize() with various combinations of
* incorrect paramters */
-
- status = MQTT_GetConnectPacketSize( NULL, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( NULL, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, NULL, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, NULL );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Verify empty connect info fails. */
memset( &connectInfo, 0x0, sizeof( connectInfo ) );
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ connectInfo.clientIdentifierLength = 1;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Verify empty client identifier fails. */
connectInfo.pClientIdentifier = CLIENT_IDENTIFIER;
connectInfo.clientIdentifierLength = 0;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Verify NULL client identifier with provided non-zero length fails. */
connectInfo.pClientIdentifier = NULL;
connectInfo.clientIdentifierLength = CLIENT_IDENTIFIER_LENGTH;
- connectInfo.cleanSession = true;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Verify empty string client ID with provided non-zero length fails. */
- connectInfo.pClientIdentifier = "";
- connectInfo.clientIdentifierLength = 99U;
- connectInfo.cleanSession = true;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Verify zero-length client identifier must have clean session. */
- connectInfo.pClientIdentifier = NULL;
- connectInfo.clientIdentifierLength = 0U;
- connectInfo.cleanSession = false;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Verify zero-length client identifier must have clean session. */
- connectInfo.pClientIdentifier = "";
- connectInfo.clientIdentifierLength = 0U;
- connectInfo.cleanSession = false;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* NULL client ID and client ID length of 0 is treated as zero-length identifier */
- connectInfo.pClientIdentifier = NULL;
- connectInfo.clientIdentifierLength = 0U;
- connectInfo.cleanSession = true;
- connectInfo.pUserName = NULL;
- connectInfo.pPassword = NULL;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure remaining size returned is 12. */
- TEST_ASSERT_EQUAL_INT( 12, remainingLength );
- /* Make sure packet size is 14. */
- TEST_ASSERT_EQUAL_INT( 14, packetSize );
-
- /* Empty string client ID and client ID length of 0 is treated as zero-length identifier */
- connectInfo.pClientIdentifier = "";
- connectInfo.clientIdentifierLength = 0U;
- connectInfo.pUserName = NULL;
- connectInfo.pPassword = NULL;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure remaining size returned is 12. */
- TEST_ASSERT_EQUAL_INT( 12, remainingLength );
- /* Make sure packet size is 14. */
- TEST_ASSERT_EQUAL_INT( 14, packetSize );
-
/* Test a will message payload length that is too large. */
- memset( &connectInfo, 0x0, sizeof( connectInfo ) );
connectInfo.pClientIdentifier = CLIENT_IDENTIFIER;
connectInfo.clientIdentifierLength = UINT16_MAX;
connectInfo.pPassword = "";
connectInfo.passwordLength = UINT16_MAX;
connectInfo.pUserName = "";
connectInfo.userNameLength = UINT16_MAX;
- willInfo.pTopicName = TEST_TOPIC_NAME;
- willInfo.topicNameLength = UINT16_MAX;
+ publishInfo.pTopicName = TEST_TOPIC_NAME;
+ publishInfo.topicNameLength = UINT16_MAX;
/* A valid will message payload is less than the maximum 16 bit integer. */
- willInfo.payloadLength = UINT16_MAX + 2;
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ publishInfo.payloadLength = UINT16_MAX + 2;
+ status = MQTT_GetConnectPacketSize( &connectInfo, &publishInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.cleanSession = true;
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 65536;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.cleanSession = true;
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ connectInfo.userNameLength = 65536;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.cleanSession = true;
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ connectInfo.passwordLength = 65536;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
/* Verify good case */
memset( &connectInfo, 0x0, sizeof( connectInfo ) );
connectInfo.cleanSession = true;
connectInfo.pClientIdentifier = "TEST";
connectInfo.clientIdentifierLength = 4;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure remaining size returned is 16. */
- TEST_ASSERT_EQUAL_INT( 16, remainingLength );
- /* Make sure packet size is 18. */
- TEST_ASSERT_EQUAL_INT( 18, packetSize );
+ /* Make sure remaining size returned is 17. */
+ TEST_ASSERT_EQUAL_INT( 17, remainingLength );
+ /* Make sure packet size is 19. */
+ TEST_ASSERT_EQUAL_INT( 19, packetSize );
+
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH;
+
+ status = MQTT_GetConnectPacketSize( &connectInfo, &publishInfo, &propBuffer, &propBuffer, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ publishInfo.pTopicName = "test";
+ publishInfo.topicNameLength = 65536;
+ publishInfo.pPayload = "testload";
+ publishInfo.payloadLength = 8;
+ status = MQTT_GetConnectPacketSize( &connectInfo, &publishInfo, NULL, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* With will. These parameters will cause the packet to be
* 4 + 2 + 8 + 2 = 16 bytes larger. */
- memset( &willInfo, 0x0, sizeof( willInfo ) );
- willInfo.pTopicName = "test";
- willInfo.topicNameLength = 4;
- willInfo.pPayload = "testload";
- willInfo.payloadLength = 8;
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ publishInfo.pTopicName = "test";
+ publishInfo.topicNameLength = 4;
+ publishInfo.pPayload = "testload";
+ publishInfo.payloadLength = 8;
+ status = MQTT_GetConnectPacketSize( &connectInfo, &publishInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure remaining size returned is 32 = 16 + 16. */
- TEST_ASSERT_EQUAL_INT( 32, remainingLength );
- /* Make sure packet size is 34 = 18 + 16. */
- TEST_ASSERT_EQUAL_INT( 34, packetSize );
+ /* Make sure remaining size returned is 32 = 16 + 16 + 2. */
+ TEST_ASSERT_EQUAL_INT( 34, remainingLength );
+ /* Make sure packet size is 34 = 18 + 16 + 2. */
+ TEST_ASSERT_EQUAL_INT( 36, packetSize );
/* With username and password. This will add 4 + 2 + 4 + 2 = 12 bytes. */
connectInfo.cleanSession = true;
@@ -563,12 +1309,37 @@ void test_MQTT_GetConnectPacketSize( void )
connectInfo.userNameLength = 4;
connectInfo.pPassword = "PASS";
connectInfo.passwordLength = 4;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* Make sure remaining size returned is 28 = 16 + 12. */
- TEST_ASSERT_EQUAL_INT( 28, remainingLength );
+ TEST_ASSERT_EQUAL_INT( 29, remainingLength );
/* Make sure packet size is 30 = 18 + 12. */
- TEST_ASSERT_EQUAL_INT( 30, packetSize );
+ TEST_ASSERT_EQUAL_INT( 31, packetSize );
+
+ propBuffer.pBuffer = NULL;
+ status = MQTT_GetConnectPacketSize( &connectInfo, &publishInfo, &propBuffer, &propBuffer, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH + 1;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &propBuffer, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH + 1;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, &propBuffer, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* With username and password. This will add 4 + 2 + 4 + 2 = 12 bytes. */
+ connectInfo.cleanSession = true;
+ connectInfo.pUserName = "USER";
+ connectInfo.userNameLength = 1;
+ connectInfo.pPassword = "PASS";
+ connectInfo.passwordLength = 1;
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH - 1;
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &propBuffer, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
}
/**
@@ -576,23 +1347,29 @@ void test_MQTT_GetConnectPacketSize( void )
*/
void test_MQTT_SerializeConnect( void )
{
- MQTTConnectInfo_t connectInfo;
+ MQTTConnectInfo_t connectInfo = { 0 };
MQTTPublishInfo_t willInfo = { 0 };
- size_t remainingLength = 0;
+ uint32_t remainingLength = 0;
uint8_t buffer[ 70 + 2 * BUFFER_PADDING_LENGTH ];
size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- size_t packetSize = bufferSize;
+ uint32_t packetSize = bufferSize;
MQTTStatus_t status = MQTTSuccess;
MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
/* Verify bad parameter errors. */
- status = MQTT_SerializeConnect( NULL, &willInfo, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( NULL, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, NULL );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
memset( &connectInfo, 0x0, sizeof( connectInfo ) );
- status = MQTT_SerializeConnect( &connectInfo, NULL, 120, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, 120, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, 120, &fixedBuffer );
TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
/* Create a good connection info. */
@@ -602,22 +1379,55 @@ void test_MQTT_SerializeConnect( void )
/* Inject a invalid fixed buffer test with a good connectInfo. */
memset( &fixedBuffer, 0x0, sizeof( fixedBuffer ) );
- status = MQTT_SerializeConnect( &connectInfo, NULL, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 65536;
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ connectInfo.userNameLength = 65536;
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ connectInfo.passwordLength = 65536;
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ memset( &willInfo, 0x00, sizeof( MQTTPublishInfo_t ) );
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
+ willInfo.pTopicName = "TOPIC";
+ willInfo.topicNameLength = 65536;
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ memset( &connectInfo, 0x0, sizeof( connectInfo ) );
+ connectInfo.pClientIdentifier = "TEST";
+ connectInfo.clientIdentifierLength = 4;
/* Good case succeeds. */
/* Set the fixedBuffer properly for the rest of the succeeding test. */
fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
fixedBuffer.size = bufferSize;
/* Calculate a good packet size. */
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
/* Make sure buffer has enough space */
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
/* Make sure test succeeds. */
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, NULL, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
@@ -627,11 +1437,11 @@ void test_MQTT_SerializeConnect( void )
connectInfo.userNameLength = 4;
connectInfo.pPassword = "PASS";
connectInfo.passwordLength = 4;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, NULL, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
@@ -642,10 +1452,10 @@ void test_MQTT_SerializeConnect( void )
willInfo.qos = MQTTQoS1;
willInfo.pPayload = "test";
willInfo.payloadLength = ( uint16_t ) strlen( willInfo.pPayload );
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
- status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, status );
/* Success. */
@@ -656,22 +1466,22 @@ void test_MQTT_SerializeConnect( void )
willInfo.topicNameLength = ( uint16_t ) strlen( willInfo.pTopicName );
willInfo.pPayload = "test";
willInfo.payloadLength = ( uint16_t ) strlen( willInfo.pPayload );
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
/* Again with QoS 2 and 0. */
willInfo.qos = MQTTQoS2;
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
@@ -680,11 +1490,11 @@ void test_MQTT_SerializeConnect( void )
/* NULL payload is acceptable. */
willInfo.pPayload = NULL;
willInfo.payloadLength = 0;
- status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, &willInfo, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
@@ -694,491 +1504,265 @@ void test_MQTT_SerializeConnect( void )
/* Throwing in a possible valid zero length password. */
connectInfo.pPassword = "PASS";
connectInfo.passwordLength = 0;
- status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &remainingLength, &packetSize );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, NULL, NULL, &remainingLength, &packetSize );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
/* Set the fixed buffer to exactly the size of the packet. */
fixedBuffer.size = packetSize;
padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeConnect( &connectInfo, NULL, remainingLength, &fixedBuffer );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, NULL, NULL, remainingLength, &fixedBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
checkBufferOverflow( buffer, sizeof( buffer ) );
-}
-/* ========================================================================== */
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
-/**
- * @brief Tests that MQTT_GetSubscribePacketSize works as intended.
- */
-void test_MQTT_GetSubscribePacketSize( void )
+ MQTTPropAdd_SessionExpiry( &propBuffer, 100, NULL );
+ status = MQTT_GetConnectPacketSize( &connectInfo, NULL, &propBuffer, NULL, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+ /* Set the fixed buffer to exactly the size of the packet. */
+ fixedBuffer.size = packetSize;
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeConnect( &connectInfo, NULL, &propBuffer, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* Testing with will property */
+ propBuffer.currentIndex = 0;
+ MQTTPropAdd_MessageExpiry( &propBuffer, 100, NULL );
+
+ status = MQTT_GetConnectPacketSize( &connectInfo, &willInfo, NULL, &propBuffer, &remainingLength, &packetSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+ /* Set the fixed buffer to exactly the size of the packet. */
+ fixedBuffer.size = packetSize;
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, &propBuffer, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* Test with null buffer*/
+ propBuffer.pBuffer = NULL;
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, NULL, &propBuffer, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ status = MQTT_SerializeConnect( &connectInfo, &willInfo, &propBuffer, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
+
+void test_RemaininglengthLimit( void )
{
- MQTTSubscribeInfo_t subscriptionList;
- size_t subscriptionCount = 1;
- size_t remainingLength = 0;
- size_t packetSize = 0;
+ /* Test will property length more than the max value allowed. */
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
+ uint32_t maxPacketSize = 100;
MQTTStatus_t status = MQTTSuccess;
- MQTTSubscribeInfo_t fourThousandSubscriptions[ 4096 ] = { 0 };
- int i;
- /* Verify parameters. */
+ publishInfo.topicNameLength = 0U;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH; /* property length == max_remaining_length */
- status = MQTT_GetSubscribePacketSize( NULL,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_GetPublishPacketSize( &publishInfo, &propBuffer, &remainingLength, &packetSize, MQTT_MAX_REMAINING_LENGTH );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- NULL,
- &packetSize );
+ status = MQTT_GetDisconnectPacketSize( &propBuffer, &remainingLength, &packetSize, maxPacketSize, 0x00 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+void test_MQTT_GetDisconnectPacketSize_InvalidPropLen( void )
+{
+ /* Test will property length more than the max value allowed. */
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
+ uint32_t maxPacketSize = 100;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTSuccessFailReasonCode_t ReasonCode = MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE;
+ publishInfo.topicNameLength = 0U;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH + 1; /* property length == max_remaining_length */
- /* Verify empty subscription list fails. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionCount = 0;
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
+ status = MQTT_GetDisconnectPacketSize( &propBuffer, &remainingLength, &packetSize, maxPacketSize, &ReasonCode );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
- /* Zero length topic filter. */
- subscriptionCount = 1;
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+void test_MQTTV5_ValidatePublishParams()
+{
+ uint16_t topicAlias = 10U;
+ uint8_t maxQos = 0U;
+ uint8_t retain = 0U;
+ uint32_t maxPacketSize = 0U;
- /* NULL topic filter, nonzero length. */
- subscriptionList.topicFilterLength = 1;
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Publish info cannot be null*/
+ status = MQTT_ValidatePublishParams( NULL, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* Verify packet size cannot exceed limit. Note the max remaining length of
- * an MQTT packet is 2^28-1 = 268435455, or 256MiB. Since the only way to increase
- * the subscribe packet size is with the topic filters of the subscriptions
- * (the lengths of which are only 2 bytes), we need at least
- * 2^28 / 2^16 = 2^12 = 4096 of them. */
- for( i = 0; i < 4096; i++ )
- {
- fourThousandSubscriptions[ i ].topicFilterLength = UINT16_MAX;
+ /* Retain is not allowed. */
+ publishInfo.retain = true;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* We need to set this to avoid an early bad parameter, however we do
- * not need a 65535 byte buffer as the packet will not be serialized. */
- fourThousandSubscriptions[ i ].pTopicFilter = "";
- }
+ /* Qos invalid*/
+ publishInfo.retain = false;
+ publishInfo.qos = 1;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- subscriptionCount = sizeof( fourThousandSubscriptions ) / sizeof( fourThousandSubscriptions[ 0 ] );
- status = MQTT_GetSubscribePacketSize( fourThousandSubscriptions,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Valid parameters except topic name length. */
+ publishInfo.qos = 1;
+ maxQos = 1;
+ publishInfo.retain = true;
+ retain = 1;
+ publishInfo.pTopicName = "abc";
+ publishInfo.topicNameLength = 65536;
+ maxPacketSize = 10;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* Verify good case. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionList.qos = MQTTQoS0;
- subscriptionList.pTopicFilter = "/example/topic";
- subscriptionList.topicFilterLength = sizeof( "/example/topic" );
- subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_GREATER_THAN( remainingLength, packetSize );
+ /* Valid parameters should return success*/
+ publishInfo.qos = 1;
+ maxQos = 1;
+ publishInfo.retain = true;
+ retain = 1;
+ publishInfo.pTopicName = "abc";
+ publishInfo.topicNameLength = 3;
+ maxPacketSize = 10;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ publishInfo.pTopicName = NULL;
+ publishInfo.topicNameLength = 0;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid topic name and topic name length*/
+ publishInfo.pTopicName = NULL;
+ publishInfo.topicNameLength = 2;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid maxPacket size*/
+ publishInfo.pTopicName = "abc";
+ publishInfo.topicNameLength = 3;
+ maxPacketSize = 0;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ maxPacketSize = 100;
+ topicAlias = 0;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ publishInfo.topicNameLength = 0;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, maxQos, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ publishInfo.pTopicName = "abc";
+ publishInfo.topicNameLength = 3;
+ publishInfo.qos = 0;
+ status = MQTT_ValidatePublishParams( &publishInfo, retain, 0, topicAlias, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
}
-/**
- * @brief Tests that MQTT_GetUnsubscribePacketSize works as intended.
- */
-void test_MQTT_GetUnsubscribePacketSize( void )
+void test_MQTTV5_GetPublishPacketSize()
{
- MQTTSubscribeInfo_t subscriptionList;
- size_t subscriptionCount = 1;
- size_t remainingLength = 0;
- size_t packetSize = 0;
- MQTTStatus_t status = MQTTSuccess;
- MQTTSubscribeInfo_t fourThousandSubscriptions[ 4096 ] = { 0 };
- int i;
+ uint32_t remainingLength = 0U;
+ uint32_t packetSize = 0U;
+ uint32_t maxPacketSize = 0U;
- /* Verify parameters. */
+ setupPublishInfo( &publishInfo );
+ /* Test with invalid paramters*/
+ status = MQTT_GetPublishPacketSize( NULL, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- status = MQTT_GetUnsubscribePacketSize( NULL,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, NULL, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- NULL,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, NULL, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Topic name invalid*/
+ publishInfo.pTopicName = NULL;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ publishInfo.pTopicName = TEST_TOPIC_NAME;
- /* Verify empty subscription list fails. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionCount = 0;
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Topic alias is not allowed and topic name is not provided. */
+ publishInfo.topicNameLength = 0;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* Zero length topic filter. */
- subscriptionCount = 1;
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ maxPacketSize = 100;
+ publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
+ /* Packet size too large*/
+ publishInfo.payloadLength = MQTT_MAX_REMAINING_LENGTH;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* NULL topic filter, nonzero length. */
- subscriptionList.topicFilterLength = 1;
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ publishInfo.payloadLength = MQTT_MAX_REMAINING_LENGTH - TEST_TOPIC_NAME_LENGTH - 4;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
- /* Verify packet size cannot exceed limit. Note the max remaining length of
- * an MQTT packet is 2^28-1 = 268435455, or 256MiB. Since the only way to increase
- * the subscribe packet size is with the topic filters of the subscriptions
- * (the lengths of which are only 2 bytes), we need at least
- * 2^28 / 2^16 = 2^12 = 4096 of them. */
- for( i = 0; i < 4096; i++ )
- {
- fourThousandSubscriptions[ i ].topicFilterLength = UINT16_MAX;
+ /* Good case succeeds. */
+ publishInfo.pPayload = "";
+ publishInfo.payloadLength = 0;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* We need to set this to avoid an early bad parameter, however we do
- * not need a 65535 byte buffer as the packet will not be serialized. */
- fourThousandSubscriptions[ i ].pTopicFilter = "";
- }
+ /* Again with QoS 2. */
+ publishInfo.qos = MQTTQoS2;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- subscriptionCount = sizeof( fourThousandSubscriptions ) / sizeof( fourThousandSubscriptions[ 0 ] );
- status = MQTT_GetUnsubscribePacketSize( fourThousandSubscriptions,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ publishInfo.retain = true;
- /* Verify good case. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionList.qos = MQTTQoS0;
- subscriptionList.pTopicFilter = "/example/topic";
- subscriptionList.topicFilterLength = sizeof( "/example/topic" );
- subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_GREATER_THAN( remainingLength, packetSize );
+ /* Valid properties*/
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 100 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+ MQTTPropAdd_TopicAlias( &propBuffer, 1, NULL );
+
+ status = MQTT_GetPublishPacketSize( &publishInfo, &propBuffer, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* No topic name*/
+ publishInfo.topicNameLength = 0U;
+ publishInfo.pTopicName = NULL;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.pBuffer = NULL;
+ status = MQTT_GetPublishPacketSize( &publishInfo, &propBuffer, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ propBuffer.pBuffer = buf;
+
+ /* Packet size is more than the server allowed max packet size*/
+ maxPacketSize = 4;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, maxPacketSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
}
/**
- * @brief Tests that MQTT_SerializeSubscribe works as intended.
+ * @brief Tests that MQTT_SerializePublish works as intended.
*/
-void test_MQTT_SerializeSubscribe( void )
-{
- MQTTSubscribeInfo_t subscriptionList;
- size_t subscriptionCount = 1;
- size_t remainingLength = 0;
- uint8_t buffer[ 25 + 2 * BUFFER_PADDING_LENGTH ];
- size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- size_t packetSize = bufferSize;
- MQTTStatus_t status = MQTTSuccess;
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
- uint8_t expectedPacket[ 100 ];
- uint8_t * pIterator = expectedPacket;
-
- const uint16_t PACKET_ID = 1;
-
- /* Verify bad parameters fail. */
- status = MQTT_SerializeSubscribe( NULL,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- status = MQTT_SerializeSubscribe( &subscriptionList,
- subscriptionCount,
- 0,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- status = MQTT_SerializeSubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Verify a NULL buffer in the fixed buffer struct fails */
- fixedBuffer.pBuffer = NULL;
- status = MQTT_SerializeSubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Restore the fixed buffer. */
- fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
-
- /* Get correct values of packet size and remaining length. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionList.qos = MQTTQoS0;
- subscriptionList.pTopicFilter = "/example/topic";
- subscriptionList.topicFilterLength = sizeof( "/example/topic" );
- subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
- status = MQTT_GetSubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure buffer has enough space */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
-
- /* Make sure subscription count of zero fails. */
- status = MQTT_SerializeSubscribe( &subscriptionList,
- 0,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Test if buffer is too small. */
- fixedBuffer.size = 1;
- status = MQTT_SerializeSubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
- fixedBuffer.size = bufferSize;
-
- /* Make sure success is returned for good case. */
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeSubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- checkBufferOverflow( buffer, sizeof( buffer ) );
-
- /* MQTT SUBSCRIBE packet format:
- * 0x82 (1 byte)
- * Remaining length (1-4 bytes)
- * Packet ID (2 bytes)
- * Topic filters (series of 2 byte lengths followed by filter, then QoS) (variable) */
- *pIterator++ = MQTT_PACKET_TYPE_SUBSCRIBE;
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
- *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
- pIterator += encodeString( pIterator, subscriptionList.pTopicFilter, subscriptionList.topicFilterLength );
- *pIterator++ = subscriptionList.qos;
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
-}
-
-/**
- * @brief Tests that MQTT_SerializeUnsubscribe works as intended.
- */
-void test_MQTT_SerializeUnsubscribe( void )
-{
- MQTTSubscribeInfo_t subscriptionList;
- size_t subscriptionCount = 1;
- size_t remainingLength = 0;
- uint8_t buffer[ 25 + 2 * BUFFER_PADDING_LENGTH ];
- size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- size_t packetSize = bufferSize;
- MQTTStatus_t status = MQTTSuccess;
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
- uint8_t expectedPacket[ 100 ];
- uint8_t * pIterator = expectedPacket;
-
- const uint16_t PACKET_ID = 1;
-
- status = MQTT_SerializeUnsubscribe( NULL,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- subscriptionCount,
- 0,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Verify a NULL buffer in the fixed buffer struct fails */
- fixedBuffer.pBuffer = NULL;
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Restore the fixed buffer. */
- fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
-
- /* Get correct values of packetsize and remaining length. */
- memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
- subscriptionList.qos = MQTTQoS0;
- subscriptionList.pTopicFilter = "/example/topic";
- subscriptionList.topicFilterLength = sizeof( "/example/topic" );
- subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
- status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
- subscriptionCount,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Make sure buffer has enough space */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
-
- /* Make sure subscription count of zero fails. */
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- 0,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
-
- /* Test if buffer is too small. */
- fixedBuffer.size = 1;
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
- fixedBuffer.size = bufferSize;
-
- /* Make sure success it returned for good case. */
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeUnsubscribe( &subscriptionList,
- subscriptionCount,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- checkBufferOverflow( buffer, sizeof( buffer ) );
-
- /* MQTT UNSUBSCRIBE packet format:
- * 0xA2 (1 byte)
- * Remaining length (1-4 bytes)
- * Packet ID (2 bytes)
- * Topic filters (series of 2 byte lengths followed by filter) (variable) */
- *pIterator++ = MQTT_PACKET_TYPE_UNSUBSCRIBE;
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
- *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
- pIterator += encodeString( pIterator, subscriptionList.pTopicFilter, subscriptionList.topicFilterLength );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
-}
-
-/* ========================================================================== */
-
-/**
- * @brief Tests that MQTT_GetPublishPacketSize works as intended.
- */
-void test_MQTT_GetPublishPacketSize( void )
-{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- size_t packetSize;
- MQTTStatus_t status = MQTTSuccess;
-
- /* Verify bad parameters fail. */
- status = MQTT_GetPublishPacketSize( NULL, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, NULL );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- /* Empty topic must fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- publishInfo.pTopicName = NULL;
- publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- publishInfo.pTopicName = TEST_TOPIC_NAME;
- publishInfo.topicNameLength = 0;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- /* Packet too large. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- publishInfo.pTopicName = "/test/topic";
- publishInfo.topicNameLength = sizeof( "/test/topic" );
- publishInfo.payloadLength = MQTT_MAX_REMAINING_LENGTH;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- publishInfo.payloadLength = MQTT_MAX_REMAINING_LENGTH - publishInfo.topicNameLength - sizeof( uint16_t ) - 1;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-
- /* Good case succeeds. */
- publishInfo.pTopicName = "/test/topic";
- publishInfo.topicNameLength = sizeof( "/test/topic" );
- publishInfo.pPayload = "";
- publishInfo.payloadLength = 0;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, status );
-
- /* Again with QoS 2. */
- publishInfo.qos = MQTTQoS2;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, status );
-}
-
-/**
- * @brief Tests that MQTT_SerializePublish works as intended.
- */
-void test_MQTT_SerializePublish( void )
+void test_MQTT_SerializePublish( void )
{
MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 98;
+ uint32_t remainingLength = 98;
uint8_t buffer[ 200 + 2 * BUFFER_PADDING_LENGTH ];
size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- size_t packetSize = bufferSize;
+ uint32_t packetSize = bufferSize;
MQTTStatus_t status = MQTTSuccess;
MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
uint8_t expectedPacket[ 200 ];
@@ -1194,12 +1778,14 @@ void test_MQTT_SerializePublish( void )
publishInfo.topicNameLength = sizeof( "/test/topic" );
status = MQTT_SerializePublish( NULL,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
NULL );
@@ -1208,6 +1794,7 @@ void test_MQTT_SerializePublish( void )
/* Verify a NULL buffer in the fixed buffer struct fails */
fixedBuffer.pBuffer = NULL;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1220,6 +1807,7 @@ void test_MQTT_SerializePublish( void )
publishInfo.payloadLength = 1;
publishInfo.pPayload = NULL;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1231,6 +1819,7 @@ void test_MQTT_SerializePublish( void )
/* Verify that 0 packet ID for QoS > 0 fails. */
publishInfo.qos = MQTTQoS1;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
0,
remainingLength,
&fixedBuffer );
@@ -1240,6 +1829,7 @@ void test_MQTT_SerializePublish( void )
publishInfo.qos = MQTTQoS0;
publishInfo.dup = true;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1253,6 +1843,7 @@ void test_MQTT_SerializePublish( void )
publishInfo.pTopicName = NULL;
publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1261,6 +1852,7 @@ void test_MQTT_SerializePublish( void )
publishInfo.pTopicName = TEST_TOPIC_NAME;
publishInfo.topicNameLength = 0;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1271,6 +1863,7 @@ void test_MQTT_SerializePublish( void )
publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
fixedBuffer.size = 5;
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
10,
&fixedBuffer );
@@ -1282,13 +1875,14 @@ void test_MQTT_SerializePublish( void )
publishInfo.topicNameLength = sizeof( "/test/topic" );
fixedBuffer.size = bufferSize;
/* Calculate exact packet size and remaining length. */
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
/* Make sure buffer has enough space */
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1301,10 +1895,12 @@ void test_MQTT_SerializePublish( void )
* Topic name length (2 bytes)
* Topic name (variable)
* Packet ID (if QoS > 0) (1 byte)
+ * Properties length (1-4 bytes) - 1 in this case
* Payload (>= 0 bytes) */
expectedPacket[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
expectedPacket[ 1 ] = remainingLength;
- ( void ) encodeString( &expectedPacket[ 2 ], publishInfo.pTopicName, publishInfo.topicNameLength );
+ ( void ) encodeStringUT( &expectedPacket[ 2 ], publishInfo.pTopicName, publishInfo.topicNameLength );
+ expectedPacket[ 16 ] = 0;
TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
/* Again with QoS2, dup, and retain. Also encode remaining length > 2 bytes. */
@@ -1317,12 +1913,13 @@ void test_MQTT_SerializePublish( void )
publishInfo.payloadLength = MQTT_SAMPLE_PAYLOAD_LEN;
memset( buffer, 0x00, bufferSize );
/* Calculate exact packet size and remaining length. */
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
/* Make sure buffer has enough space */
TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
padAndResetBuffer( buffer, sizeof( buffer ) );
status = MQTT_SerializePublish( &publishInfo,
+ NULL,
PACKET_ID,
remainingLength,
&fixedBuffer );
@@ -1332,550 +1929,512 @@ void test_MQTT_SerializePublish( void )
pIterator = expectedPacket;
/* Set the flags as follows: Dup = 0x8, QoS2 = 0x4, Retain = 0x1. 8 | 4 | 1 = 0xD. */
*pIterator++ = MQTT_PACKET_TYPE_PUBLISH | 0xD;
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- pIterator += encodeString( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ pIterator += encodeStringUT( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
*pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
*pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0;
( void ) memcpy( pIterator, publishInfo.pPayload, publishInfo.payloadLength );
TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
}
/* ========================================================================== */
-/**
- * @brief Tests that MQTT_GetDisconnectPacketSize works as intended.
- */
-void test_MQTT_GetDisconnectPacketSize( void )
+void test_MQTTV5_DeserializeAck_puback( void )
{
- MQTTStatus_t status;
- size_t packetSize;
+ MQTTPacketInfo_t mqttPacketInfo;
+ MQTTReasonCodeInfo_t ackInfo;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint16_t packetIdentifier;
+ uint32_t maxPacketSize = 0U;
+ bool requestProblem = false;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buffer[ 100 ] = { 0 };
+ uint8_t * pIndex = buffer;
+ size_t dummy;
- /* Verify parameters. */
- status = MQTT_GetDisconnectPacketSize( NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Verify parameters */
+ memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+ memset( &ackInfo, 0x00, sizeof( ackInfo ) );
+ memset( &properties, 0x00, sizeof( properties ) );
- /* Good case succeeds. A DISCONNECT is 2 bytes. */
- status = MQTT_GetDisconnectPacketSize( &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 2, packetSize );
-}
-
-/**
- * @brief Tests that MQTT_SerializeDisconnect works as intended.
- */
-void test_MQTT_SerializeDisconnect( void )
-{
- uint8_t buffer[ 10 + 2 * BUFFER_PADDING_LENGTH ];
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ] };
- uint8_t expectedPacket[ 2 ] = { MQTT_PACKET_TYPE_DISCONNECT, 0 };
- MQTTStatus_t status = MQTTSuccess;
-
- /* Buffer size less than disconnect request fails. */
- fixedBuffer.size = 1;
- status = MQTT_SerializeDisconnect( &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+ properties.requestProblemInfo = requestProblem;
+ properties.maxPacketSize = maxPacketSize;
- /* NULL buffer fails. */
- status = MQTT_SerializeDisconnect( NULL );
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBACK;
+ status = MQTT_DeserializeAck( NULL, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Good case succeeds. */
- fixedBuffer.size = 2;
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeDisconnect( &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- checkBufferOverflow( buffer, sizeof( buffer ) );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], 2 );
-}
-
-/**
- * @brief Tests that MQTT_GetPingreqPacketSize works as intended.
- */
-void test_MQTT_GetPingreqPacketSize( void )
-{
- MQTTStatus_t status;
- size_t packetSize;
-
- /* Verify parameters. */
- status = MQTT_GetPingreqPacketSize( NULL );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Good case succeeds. A PINGREQ is 2 bytes. */
- status = MQTT_GetPingreqPacketSize( &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 2, packetSize );
-}
-
-/**
- * @brief Tests that MQTT_SerializePingreq works as intended.
- */
-void test_MQTT_SerializePingreq( void )
-{
- uint8_t buffer[ 10 + 2 * BUFFER_PADDING_LENGTH ];
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ] };
- uint8_t expectedPacket[ 2 ] = { MQTT_PACKET_TYPE_PINGREQ, 0 };
- MQTTStatus_t status = MQTTSuccess;
-
- /* Buffer size less than ping request fails. */
- fixedBuffer.size = 1;
- status = MQTT_SerializePingreq( &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* NULL buffer fails. */
- status = MQTT_SerializePingreq( NULL );
+ /* Remaining data cannot be NULL. */
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Verify a NULL buffer in the fixed buffer struct fails */
- fixedBuffer.pBuffer = NULL;
- status = MQTT_SerializePingreq( &fixedBuffer );
+ /* Max packet size cannot be 0*/
+ mqttPacketInfo.pRemainingData = buffer;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Restore the fixed buffer. */
- fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Good case succeeds. */
- fixedBuffer.size = 2;
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializePingreq( &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- checkBufferOverflow( buffer, sizeof( buffer ) );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], 2 );
-}
+ maxPacketSize = 200U;
+ properties.maxPacketSize = maxPacketSize;
+ /* Packet identifier 0 is not valid (per spec). */
+ buffer[ 0 ] = 0;
+ buffer[ 1 ] = 0;
+ mqttPacketInfo.remainingLength = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
-/* ========================================================================== */
+ /* Remaining length connot be less than 2*/
+ mqttPacketInfo.remainingLength = 1;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
-/**
- * @brief Tests that MQTT_DeserializeAck works as intended with a CONNACK.
- */
-void test_MQTT_DeserializeAck_connack( void )
-{
- MQTTPacketInfo_t mqttPacketInfo;
- uint16_t packetIdentifier;
- bool sessionPresent = true;
- MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 10 ];
+ /* Packet size greater than allowed. */
+ mqttPacketInfo.remainingLength = 1000U;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Verify parameters */
- memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+ /* Should fail to process CONNACK. */
mqttPacketInfo.type = MQTT_PACKET_TYPE_CONNACK;
- status = MQTT_DeserializeAck( NULL, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Packet ID can be NULL for CONNACK, don't need to check that. */
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, NULL );
+ mqttPacketInfo.remainingLength = 2;
+ buffer[ 1 ] = 1;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ /* Process a valid PUBACK. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBACK;
+ mqttPacketInfo.remainingLength = 2;
+ buffer[ 1 ] = 1;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
- /* Bad packet type. */
- mqttPacketInfo.type = 0x01;
- mqttPacketInfo.pRemainingData = buffer;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ mqttPacketInfo.remainingLength = 3;
+ buffer[ 2 ] = 0x00;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
- /* Bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_CONNACK;
- mqttPacketInfo.remainingLength = MQTT_PACKET_CONNACK_REMAINING_LENGTH - 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ /* Property length should be zero when request problem is set to false*/
+ mqttPacketInfo.remainingLength = 24;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Incorrect reserved bits. */
- mqttPacketInfo.remainingLength = MQTT_PACKET_CONNACK_REMAINING_LENGTH;
- buffer[ 0 ] = 0xf;
- buffer[ 1 ] = 0;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ requestProblem = true;
+ properties.requestProblemInfo = requestProblem;
+ /* User properties not initialized. */
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Session present but nonzero return code. */
- buffer[ 0 ] = MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK;
- buffer[ 1 ] = 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ /* Valid parameters. */
+ pIndex = &buffer[ 3 ];
+ dummy = encodeVariableLengthUT( pIndex, 20 );
+ pIndex++;
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Invalid response code. */
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 6;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ /* With NULL prop builder. */
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Valid packet with rejected code. */
- buffer[ 1 ] = 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+ /* Invalid property id*/
+ pIndex = &buffer[ 3 ];
+ dummy = encodeVariableLengthUT( pIndex, 7 );
+ mqttPacketInfo.remainingLength = dummy + 7 + 3;
+ pIndex++;
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Valid packet with success code when session present bit is set. */
- buffer[ 0 ] = MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK;
- buffer[ 1 ] = 0;
- sessionPresent = false;
- status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( true, sessionPresent );
+ /* Invalid remaining length*/
+ pIndex = &buffer[ 3 ];
+ dummy = encodeVariableLengthUT( pIndex, 12 );
+ pIndex++;
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Valid packet with success code when session present bit is not set. */
- buffer[ 0 ] = 0;
- status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( false, sessionPresent );
+ /* Invalid property length*/
+ pIndex = &buffer[ 3 ];
+ dummy = encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
}
-/**
- * @brief Tests that MQTT_DeserializeAck works as intended with a SUBACK.
- */
-void test_MQTT_DeserializeAck_suback( void )
+void test_MQTTV5_DeserializeAck_LogPuback()
{
MQTTPacketInfo_t mqttPacketInfo;
+ MQTTReasonCodeInfo_t ackInfo;
uint16_t packetIdentifier;
- bool sessionPresent;
+ uint32_t maxPacketSize = 10U;
+ bool requestProblem = false;
MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 10 ] = { 0 };
+ uint8_t buffer[ 4 ] = { 0 };
- /* Bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
- mqttPacketInfo.pRemainingData = buffer;
- mqttPacketInfo.remainingLength = 2;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+ memset( &ackInfo, 0x00, sizeof( ackInfo ) );
+ memset( &properties, 0x00, sizeof( properties ) );
+ properties.requestProblemInfo = requestProblem;
+ properties.maxPacketSize = maxPacketSize;
- /* Invalid packet ID. */
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 0;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ mqttPacketInfo.pRemainingData = buffer;
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBACK;
mqttPacketInfo.remainingLength = 3;
- buffer[ 2 ] = 0;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
-
- /* Set packet identifier. */
- buffer[ 0 ] = 0;
+ /* Validate all the correct reason codes. */
buffer[ 1 ] = 1;
+ buffer[ 2 ] = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Bad response code. */
- mqttPacketInfo.remainingLength = 3;
- buffer[ 2 ] = 5;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Process a valid SUBACK with server refused response code. */
- mqttPacketInfo.remainingLength = 3;
- buffer[ 2 ] = 0x80;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_UNSPECIFIED_ERROR;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_UNSPECIFIED_ERROR, *ackInfo.reasonCode );
- /* Process a valid SUBACK with various server acceptance codes. */
- mqttPacketInfo.remainingLength = 5;
- buffer[ 2 ] = 0x00;
- buffer[ 3 ] = 0x01;
- buffer[ 4 ] = 0x02;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
-}
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR, *ackInfo.reasonCode );
-/**
- * @brief Tests that MQTT_DeserializeAck works as intended with an UNSUBACK.
- */
-void test_MQTT_DeserializeAck_unsuback( void )
-{
- MQTTPacketInfo_t mqttPacketInfo;
- uint16_t packetIdentifier;
- bool sessionPresent;
- MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 10 ] = { 0 };
+ buffer[ 2 ] = MQTT_REASON_PUBACK_NOT_AUTHORIZED;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_NOT_AUTHORIZED, *ackInfo.reasonCode );
- /* Bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_UNSUBACK;
- mqttPacketInfo.pRemainingData = buffer;
- mqttPacketInfo.remainingLength = MQTT_PACKET_UNSUBACK_REMAINING_LENGTH - 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_TOPIC_NAME_INVALID;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_TOPIC_NAME_INVALID, *ackInfo.reasonCode );
- /* Packet identifier 0 is not valid (per spec). */
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 0;
- mqttPacketInfo.remainingLength = MQTT_PACKET_UNSUBACK_REMAINING_LENGTH;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE, *ackInfo.reasonCode );
- /* Process a valid UNSUBACK. */
- buffer[ 1 ] = 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ buffer[ 2 ] = MQTT_REASON_PUBACK_QUOTA_EXCEEDED;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
-}
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_QUOTA_EXCEEDED, *ackInfo.reasonCode );
-/**
- * @brief Tests that MQTT_DeserializeAck works as intended with a PINGRESP.
- */
-void test_MQTT_DeserializeAck_pingresp( void )
-{
- MQTTPacketInfo_t mqttPacketInfo;
- uint16_t packetIdentifier;
- bool sessionPresent;
- MQTTStatus_t status = MQTTSuccess;
+ buffer[ 2 ] = MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID, *ackInfo.reasonCode );
- /* Bad remaining length. */
- ( void ) memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PINGRESP;
- mqttPacketInfo.remainingLength = MQTT_PACKET_PINGRESP_REMAINING_LENGTH + 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ /* Invalid reason code. */
+ buffer[ 2 ] = MQTT_REASON_CONNACK_BANNED;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
-
- /* Process a valid PINGRESP. */
- mqttPacketInfo.remainingLength = MQTT_PACKET_PINGRESP_REMAINING_LENGTH;
- mqttPacketInfo.pRemainingData = NULL;
- status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, NULL );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief Tests that MQTT_DeserializeAck works as intended with a PUBACK,
- * PUBREC, PUBREL, and PUBCOMP.
- */
-void test_MQTT_DeserializeAck_puback( void )
+void test_MQTTV5_DeserializeAck_Pubrel()
{
MQTTPacketInfo_t mqttPacketInfo;
+ MQTTReasonCodeInfo_t ackInfo;
+ uint32_t maxPacketSize = 10U;
uint16_t packetIdentifier;
- bool sessionPresent;
+ bool requestProblem = false;
MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 10 ] = { 0 };
+ MQTTPropBuilder_t propBuffer;
+ uint8_t buffer[ 4 ] = { 0 };
- /* Verify parameters */
memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBACK;
- status = MQTT_DeserializeAck( NULL, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* mqttPacketInfo.pRemainingData not set. */
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ memset( &ackInfo, 0x00, sizeof( ackInfo ) );
+ memset( &properties, 0x00, sizeof( properties ) );
+ properties.requestProblemInfo = requestProblem;
+ properties.maxPacketSize = maxPacketSize;
- /* Bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBACK;
mqttPacketInfo.pRemainingData = buffer;
- mqttPacketInfo.remainingLength = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH - 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBREL;
+ mqttPacketInfo.remainingLength = 3;
+ /* Validate all the correct reason codes. */
+ buffer[ 1 ] = 1;
+ buffer[ 2 ] = MQTT_REASON_PUBREL_SUCCESS;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ buffer[ 2 ] = MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT8( MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND, *ackInfo.reasonCode );
+
+ /* Invalid reason code. */
+ buffer[ 2 ] = MQTT_REASON_CONNACK_BANNED;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Packet identifier 0 is not valid (per spec). */
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 0;
- mqttPacketInfo.remainingLength = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ /* Invalid reason code. */
+ buffer[ 2 ] = MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Process a valid PUBACK. */
- buffer[ 1 ] = 1;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
+ /* Invalid packet id*/
+ buffer[ 1 ] = 0;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* PUBREC. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBREC;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
+ /* Invalid packet type. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_DISCONNECT;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* PUBREL. */
mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBREL;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
-
- /* PUBCOMP. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBCOMP;
- status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &sessionPresent );
+ buffer[ 1 ] = 1; /* Reset packet identifier to a valid value. */
+ mqttPacketInfo.remainingLength = 2;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &ackInfo, &propBuffer, &properties );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 1, packetIdentifier );
}
-/* ========================================================================== */
-
-/**
- * @brief Tests that MQTT_DeserializePublish works as intended.
- */
-void test_MQTT_DeserializePublish( void )
+void test_MQTTV5_GetAckPacketSize()
{
- MQTTPacketInfo_t mqttPacketInfo;
- MQTTPublishInfo_t publishInfo;
- MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 100 ];
- size_t bufferSize = sizeof( buffer );
- MQTTFixedBuffer_t fixedBuffer = { 0 };
- size_t packetSize = bufferSize;
-
- size_t remainingLength = 0;
- uint16_t packetIdentifier;
-
- fixedBuffer.pBuffer = buffer;
- fixedBuffer.size = bufferSize;
-
- const uint16_t PACKET_ID = 1;
-
- memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+ MQTTStatus_t status;
+ uint32_t remainingLength;
+ uint32_t packetSize;
+ uint32_t maxPacketSize = 0U;
- /* Verify parameters. */
- status = MQTT_DeserializePublish( NULL, &packetIdentifier, &publishInfo );
+ /* Invalid parameters*/
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_DeserializePublish( &mqttPacketInfo, NULL, &publishInfo );
+
+ status = MQTT_GetAckPacketSize( NULL, &packetSize, maxPacketSize, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, NULL );
+
+ status = MQTT_GetAckPacketSize( &remainingLength, NULL, maxPacketSize, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
+ /* Max packet size cannot be 0*/
+ status = MQTT_GetAckPacketSize( &remainingLength, NULL, maxPacketSize, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Bad Packet Type. */
- mqttPacketInfo.type = 0x01;
- mqttPacketInfo.pRemainingData = buffer;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
+ /* Valid parameters*/
+ maxPacketSize = UINT32_MAX;
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, 0 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* With properties*/
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, 10 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* With invalid ack prop length. */
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, MQTT_MAX_REMAINING_LENGTH + 1 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Incorrect flags. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0xf;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ /* Packet size greater than max allowed. */
+ maxPacketSize = 2;
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, 0 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* QoS 0 bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
- mqttPacketInfo.remainingLength = 0;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ /* Max packet size cannot be 0*/
+ maxPacketSize = 0;
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, 0 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* QoS 1 bad remaining length. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0x2;
- mqttPacketInfo.remainingLength = 0;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ maxPacketSize = 500;
+ status = MQTT_GetAckPacketSize( &remainingLength, &packetSize, maxPacketSize, MQTT_MAX_REMAINING_LENGTH );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
- /* QoS 1 invalid packet identifier. */
- mqttPacketInfo.remainingLength = 5;
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 1;
- buffer[ 2 ] = ( uint8_t ) 'a';
- buffer[ 3 ] = 0;
- buffer[ 4 ] = 0;
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
- TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+void test_MQTTV5_GetDisconnectPacketSize()
+{
+ uint32_t remainingLength;
+ uint32_t packetSize;
+ uint32_t maxPacketSize = 0U;
+ MQTTStatus_t status;
+ MQTTSuccessFailReasonCode_t reasonCode;
- /* Create a PUBLISH packet to test. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- setupPublishInfo( &publishInfo );
+ /* Invalid arguments*/
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Test serialization and deserialization of a QoS 0 PUBLISH. */
- publishInfo.qos = MQTTQoS0;
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( NULL, NULL, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, NULL, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Max packet size cannot be 0. */
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Invalid Reason code. */
+ maxPacketSize = 60U;
+ reasonCode = MQTT_REASON_SUBACK_GRANTED_QOS1;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Generate QoS 0 packet. */
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
+ /* Valid parameters*/
+ reasonCode = MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
- status = MQTT_SerializePublish( &publishInfo,
- 0,
- remainingLength,
- &fixedBuffer );
+ /* Valid parameters*/
+ reasonCode = MQTT_REASON_DISCONNECT_PACKET_TOO_LARGE;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- /* Deserialize QoS 0 packet. */
- mqttPacketInfo.type = buffer[ 0 ];
+ /* Invalid reason code. */
+ reasonCode = MQTT_REASON_DISCONNECT_SERVER_BUSY;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* We don't need to go through the trouble of calling MQTT_GetIncomingPacketTypeAndLength.
- * We know the remaining length is < 128. */
- mqttPacketInfo.remainingLength = ( size_t ) buffer[ 1 ];
- mqttPacketInfo.pRemainingData = &buffer[ 2 ];
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( TEST_TOPIC_NAME_LENGTH, publishInfo.topicNameLength );
- TEST_ASSERT_EQUAL_MEMORY( TEST_TOPIC_NAME, publishInfo.pTopicName, TEST_TOPIC_NAME_LENGTH );
- TEST_ASSERT_EQUAL_INT( MQTT_SAMPLE_PAYLOAD_LEN, publishInfo.payloadLength );
- TEST_ASSERT_EQUAL_MEMORY( MQTT_SAMPLE_PAYLOAD, publishInfo.pPayload, MQTT_SAMPLE_PAYLOAD_LEN );
+ /* Max packet size lesser than packet size */
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+ propBuffer.currentIndex = 10;
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( &propBuffer, &remainingLength, &packetSize, 6, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
- /* Reset publish info since its pointers now point to our serialized buffer. */
- setupPublishInfo( &publishInfo );
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH; /* Other fields do not have to be set as we only testing if the length of properties == max_remaining_length */
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( &propBuffer, &remainingLength, &packetSize, maxPacketSize, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Test serialization and deserialization of a QoS 1 PUBLISH. */
- publishInfo.qos = MQTTQoS1;
- /* Mark the publish as duplicate. */
- publishInfo.dup = true;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
+ propBuffer.pBuffer = NULL;
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_GetDisconnectPacketSize( &propBuffer, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE, &reasonCode );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+}
- status = MQTT_SerializePublish( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
+void test_MQTTV5_DeserializeDisconnect()
+{
+ MQTTReasonCodeInfo_t disconnectInfo;
+ size_t dummy;
+ int32_t maxPacketSize = 0U;
+ uint8_t buffer[ 100 ] = { 0 };
+ uint8_t * pIndex = buffer;
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ memset( &disconnectInfo, 0x0, sizeof( disconnectInfo ) );
+ /* Invalid parameters*/
+ status = MQTT_DeserializeDisconnect( NULL, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Remaining data not initialized. */
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ packetInfo.pRemainingData = buffer;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, NULL, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Max packet size cannot be 0. */
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ maxPacketSize = 100;
+
+ /* Remaining length can be 0*/
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- mqttPacketInfo.type = buffer[ 0 ];
- mqttPacketInfo.remainingLength = ( size_t ) buffer[ 1 ];
- mqttPacketInfo.pRemainingData = &buffer[ 2 ];
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
+ /* Remaining Length invalid. */
+ packetInfo.remainingLength = 200;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid reason code. */
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ packetInfo.remainingLength = 1;
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_NOT_AUTHORIZED;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_TRUE( publishInfo.dup );
- TEST_ASSERT_EQUAL_INT( TEST_TOPIC_NAME_LENGTH, publishInfo.topicNameLength );
- TEST_ASSERT_EQUAL_MEMORY( TEST_TOPIC_NAME, publishInfo.pTopicName, TEST_TOPIC_NAME_LENGTH );
- TEST_ASSERT_EQUAL_INT( MQTT_SAMPLE_PAYLOAD_LEN, publishInfo.payloadLength );
- TEST_ASSERT_EQUAL_MEMORY( MQTT_SAMPLE_PAYLOAD, publishInfo.pPayload, MQTT_SAMPLE_PAYLOAD_LEN );
- /* QoS 2 PUBLISH. */
- setupPublishInfo( &publishInfo );
- publishInfo.qos = MQTTQoS2;
- /* Remaining length and packet size should be same as before. */
- status = MQTT_SerializePublish( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer );
+ /* Property length is 0. */
+ packetInfo.remainingLength = 2;
+ pIndex = &buffer[ 1 ];
+ dummy = encodeVariableLengthUT( pIndex, 0 );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- mqttPacketInfo.type = buffer[ 0 ];
- mqttPacketInfo.remainingLength = ( size_t ) buffer[ 1 ];
- mqttPacketInfo.pRemainingData = &buffer[ 2 ];
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
+
+ /* With properties*/
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ pIndex = &buffer[ 1 ];
+ packetInfo.remainingLength = 29;
+ dummy = encodeVariableLengthUT( pIndex, 27 );
+ pIndex++;
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeutf_8( pIndex, MQTT_SERVER_REF_ID );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( TEST_TOPIC_NAME_LENGTH, publishInfo.topicNameLength );
- TEST_ASSERT_EQUAL_MEMORY( TEST_TOPIC_NAME, publishInfo.pTopicName, TEST_TOPIC_NAME_LENGTH );
- TEST_ASSERT_EQUAL_INT( MQTT_SAMPLE_PAYLOAD_LEN, publishInfo.payloadLength );
- TEST_ASSERT_EQUAL_MEMORY( MQTT_SAMPLE_PAYLOAD, publishInfo.pPayload, MQTT_SAMPLE_PAYLOAD_LEN );
- /* Zero length payload. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- publishInfo.pTopicName = TEST_TOPIC_NAME;
- publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
- publishInfo.payloadLength = 0;
- publishInfo.qos = MQTTQoS0;
+ /* Invalid reason code for incoming DISCONNECT packet. */
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_DISCONNECT_WITH_WILL_MESSAGE;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
- /* Generate packet. */
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+ /* Invalid property id. */
+ pIndex = &buffer[ 1 ];
+ packetInfo.remainingLength = 9;
+ dummy = encodeVariableLengthUT( pIndex, 7 );
+ pIndex++;
+ pIndex = serializeutf_8( pIndex, MQTT_SESSION_EXPIRY_ID );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ TEST_ASSERT_EQUAL_INT( 1, dummy );
- status = MQTT_SerializePublish( &publishInfo,
- 0,
- remainingLength,
- &fixedBuffer );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Invalid property length. */
+ pIndex = &buffer[ 1 ];
+ packetInfo.remainingLength = 9;
+ dummy = encodeVariableLengthUT( pIndex, 4 );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- /* Deserialize packet. */
- mqttPacketInfo.type = buffer[ 0 ];
- mqttPacketInfo.remainingLength = ( size_t ) buffer[ 1 ];
- mqttPacketInfo.pRemainingData = &buffer[ 2 ];
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo );
+ /* Invalid property length. */
+ buffer[ 1 ] = 0x81;
+ buffer[ 2 ] = 0x00;
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, &propBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Property length is 0. */
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ pIndex = &buffer[ 1 ];
+ packetInfo.remainingLength = 2;
+ dummy = encodeVariableLengthUT( pIndex, 0 );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( TEST_TOPIC_NAME_LENGTH, publishInfo.topicNameLength );
- TEST_ASSERT_EQUAL_MEMORY( TEST_TOPIC_NAME, publishInfo.pTopicName, TEST_TOPIC_NAME_LENGTH );
- TEST_ASSERT_EQUAL_INT( 0, publishInfo.payloadLength );
- TEST_ASSERT_NULL( publishInfo.pPayload );
-}
-/* ========================================================================== */
+ /* RemainingLength length is invalid. */
+ buffer[ 0 ] = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ pIndex = &buffer[ 1 ];
+ packetInfo.remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+ dummy = encodeVariableLengthUT( pIndex, 0 );
+ status = MQTT_DeserializeDisconnect( &packetInfo, maxPacketSize, &disconnectInfo, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
-/**
- * @brief Tests that MQTT_GetIncomingPacketTypeAndLength works as intended.
- */
void test_MQTT_GetIncomingPacketTypeAndLength( void )
{
- MQTTStatus_t status = MQTTSuccess;
MQTTPacketInfo_t mqttPacket;
NetworkContext_t networkContext;
uint8_t buffer[ 10 ];
@@ -1883,1087 +2442,5677 @@ void test_MQTT_GetIncomingPacketTypeAndLength( void )
/* Dummy network context - pointer to pointer to a buffer. */
networkContext.buffer = &bufPtr;
+ /* Check when network receive fails. */
+ memset( buffer, 0x00, 10 );
+ /* Branch coverage for Disconnect. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
- /* Test a NULL pIncomingPacket parameter. */
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+void test_MQTTV5_GetSubscribePacketSize( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTSubscribeInfo_t subscribeInfo;
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
- /* Test a typical happy path case for a CONN ACK packet. */
- buffer[ 0 ] = 0x20; /* CONN ACK */
- buffer[ 1 ] = 0x02; /* Remaining length. */
+ /** Verify Parameters */
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( 0x20, mqttPacket.type );
- TEST_ASSERT_EQUAL_INT( 0x02, mqttPacket.remainingLength );
+ /** NULL parameters */
+ status = MQTT_GetSubscribePacketSize( NULL, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Remaining length of 128. MQTT uses 7 bits for data and 1 continuation
- * bit in each byte. Since 128 is 8 bits, it needs 2 bytes. */
- bufPtr = buffer;
- buffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
- buffer[ 1 ] = 0x80; /* LSB: CB=1, value=0x00 */
- buffer[ 2 ] = 0x01; /* MSB: CB=0, value=0x01 */
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( MQTT_PACKET_TYPE_PUBLISH, mqttPacket.type );
- TEST_ASSERT_EQUAL_INT( 128, mqttPacket.remainingLength );
+ /** NULL remaining length. */
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, NULL, NULL, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Remaining length of 16384. MQTT uses 7 bits for data and 1 continuation
- * bit in each byte. Since 16384 is 15 bits, it needs 3 bytes. */
- bufPtr = buffer;
- buffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
- buffer[ 1 ] = 0x80; /* LSB : CB=1, value=0x00 */
- buffer[ 2 ] = 0x80; /* Byte 1: CB=1, value=0x00 */
- buffer[ 3 ] = 0x01; /* MSB : CB=0, value=0x01 */
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_INT( MQTT_PACKET_TYPE_PUBLISH, mqttPacket.type );
- TEST_ASSERT_EQUAL_INT( 16384, mqttPacket.remainingLength );
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 0, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Test with incorrect packet type. */
- bufPtr = buffer;
- buffer[ 0 ] = 0x10; /* INVALID */
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+ subscribeInfo.topicFilterLength = 13;
+ subscribeInfo.pTopicFilter = "example/topic";
- /* Test with invalid remaining length. */
- bufPtr = buffer;
- buffer[ 0 ] = 0x20; /* CONN ACK */
+ /* Invalid max packet size*/
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, 0 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* To generate invalid remaining length response,
- * four bytes need to have MSB (or continuation bit, 0x80) set */
- buffer[ 1 ] = 0xFF;
- buffer[ 2 ] = 0xFF;
- buffer[ 3 ] = 0xFF;
- buffer[ 4 ] = 0xFF;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = MQTT_MAX_REMAINING_LENGTH + 1;
+ /* Invalid current index. */
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, &propBuffer, &remainingLength, &packetSize, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Check with an encoding that does not conform to the MQTT spec. */
- bufPtr = buffer;
- buffer[ 1 ] = 0x80;
- buffer[ 2 ] = 0x80;
- buffer[ 3 ] = 0x80;
- buffer[ 4 ] = 0x00;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+ /* Invalid topic length. */
+ subscribeInfo.topicFilterLength = 65536;
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Check when network receive fails. */
- memset( buffer, 0x00, 10 );
- bufPtr = buffer;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveFailure, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTRecvFailed, status );
+ subscribeInfo.topicFilterLength = MQTT_MAX_REMAINING_LENGTH;
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Test if no data is available. */
- bufPtr = buffer;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveNoData, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTNoDataAvailable, status );
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, 10 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
- /* Branch coverage for PUBREL. */
- bufPtr = buffer;
- buffer[ 0 ] = MQTT_PACKET_TYPE_PUBREL & 0xF0U;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+void test_MQTTV5_GetSubscribePacketSize_HappyPath( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTSubscribeInfo_t subscribeInfo;
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
+
+ subscribeInfo.pTopicFilter = TEST_TOPIC_NAME;
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+ subscribeInfo.qos = MQTTQoS0;
+ subscribeInfo.noLocalOption = 0;
+ subscribeInfo.retainAsPublishedOption = 0;
+ subscribeInfo.retainHandlingOption = 1;
+
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 2;
+
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, &propBuffer, &remainingLength, &packetSize, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT32( 19U, remainingLength );
+ TEST_ASSERT_EQUAL_UINT32( 21U, packetSize );
- /* Receive type then fail. */
- bufPtr = buffer;
- buffer[ 0 ] = MQTT_PACKET_TYPE_PUBREL;
- status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveSucceedThenFail, &networkContext, &mqttPacket );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+ /* Test function with null buffer. */
+ propBuffer.pBuffer = NULL;
+ status = MQTT_GetSubscribePacketSize( &subscribeInfo, 1, &propBuffer, &remainingLength, &packetSize, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/* ========================================================================== */
+/** Subscribe Packet size with multiple subscriptions and User Properties */
+void test_MQTTV5_GetSubscribePacketSize_MultipleSubscriptions( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTSubscribeInfo_t subscribeInfo[ 2 ];
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
+
+ subscribeInfo[ 0 ].pTopicFilter = TEST_TOPIC_NAME;
+ subscribeInfo[ 0 ].topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+ subscribeInfo[ 0 ].qos = MQTTQoS0;
+ subscribeInfo[ 0 ].noLocalOption = 0;
+ subscribeInfo[ 0 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 0 ].retainHandlingOption = 1;
+
+ subscribeInfo[ 1 ].pTopicFilter = TEST_TOPIC_NAME;
+ subscribeInfo[ 1 ].topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+ subscribeInfo[ 1 ].qos = MQTTQoS0;
+ subscribeInfo[ 1 ].noLocalOption = 0;
+ subscribeInfo[ 1 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 1 ].retainHandlingOption = 1;
+
+ status = MQTT_GetSubscribePacketSize( subscribeInfo, 2, NULL, &remainingLength, &packetSize, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
-/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
- */
-void test_MQTT_SerializePublishHeaderWithoutTopic_AllNULL( void )
+void test_calculateSubscriptionPacketSizeV5( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
+ size_t subscriptionCount = 1;
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ MQTTSubscribeInfo_t fourThousandSubscriptions[ 4096 ] = { 0 };
+ int i;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ for( i = 0; i < 4096; i++ )
+ {
+ fourThousandSubscriptions[ i ].topicFilterLength = UINT16_MAX;
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ /* We need to set this to avoid an early bad parameter, however we do
+ * not need a 65535 byte buffer as the packet will not be serialized. */
+ fourThousandSubscriptions[ i ].pTopicFilter = "";
+ }
- TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set. Except publish flag. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+ subscriptionCount = sizeof( fourThousandSubscriptions ) / sizeof( fourThousandSubscriptions[ 0 ] );
+ status = MQTT_GetSubscribePacketSize( fourThousandSubscriptions,
+ subscriptionCount,
+ NULL,
+ &remainingLength,
+ &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/* ========================================================================== */
-
/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ * @brief Tests that MQTT_SerializeSubscribe works as intended.
*/
-void test_MQTT_SerializePublishHeaderWithoutTopic_QoS1( void )
+void test_MQTT_SerializeSubscribe( void )
+{
+ MQTTSubscribeInfo_t subscriptionList;
+ size_t subscriptionCount = 1;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 25 + 2 * BUFFER_PADDING_LENGTH ];
+ size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
+ uint32_t packetSize = bufferSize;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
+ uint8_t expectedPacket[ 100 ];
+ uint8_t * pIterator = expectedPacket;
+
+ const uint16_t PACKET_ID = 1;
+
+ /* Verify bad parameters fail. */
+ status = MQTT_SerializeSubscribe( NULL,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ 0,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Verify a NULL buffer in the fixed buffer struct fails */
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Restore the fixed buffer. */
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+
+ /* Get correct values of packet size and remaining length. */
+ memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
+ subscriptionList.qos = MQTTQoS0;
+ subscriptionList.pTopicFilter = "/example/topic";
+ subscriptionList.topicFilterLength = sizeof( "/example/topic" );
+ subscriptionList.noLocalOption = 1;
+ subscriptionList.retainAsPublishedOption = 1;
+ subscriptionList.retainHandlingOption = 1;
+ uint32_t maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
+ status = MQTT_GetSubscribePacketSize( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ &remainingLength,
+ &packetSize,
+ maxPacketSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+
+ /* Make sure subscription count of zero fails. */
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ 0,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Test if buffer is too small. */
+ fixedBuffer.size = 1;
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+ fixedBuffer.size = bufferSize;
+
+ /* Make sure success is returned for good case. */
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* MQTT SUBSCRIBE packet format:
+ * 0x82 (1 byte)
+ * Remaining length (1-4 bytes)
+ * Packet ID (2 bytes)
+ * Topic filters (series of 2 byte lengths followed by filter, then QoS) (variable) */
+ /* uint8_t subscriptionOptions = 0 ; */
+ /* subscriptionOptions = subscriptionOptions & */
+ *pIterator++ = MQTT_PACKET_TYPE_SUBSCRIBE;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
+ *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0; /* Length of properties = 0 */
+ pIterator += encodeStringUT( pIterator, subscriptionList.pTopicFilter, subscriptionList.topicFilterLength );
+ *pIterator++ = 0x1C;
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ subscriptionList.noLocalOption = 0;
+ subscriptionList.retainAsPublishedOption = 0;
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ pIterator = expectedPacket;
+ *pIterator++ = MQTT_PACKET_TYPE_SUBSCRIBE;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
+ *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0; /* Length of properties = 0 */
+ pIterator += encodeStringUT( pIterator, subscriptionList.pTopicFilter, subscriptionList.topicFilterLength );
+ *pIterator++ = 0x10;
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+
+ /* Serialize subscribe with properties */
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+
+ MQTTPropAdd_SubscriptionId( &propBuffer, 10, NULL );
+ status = MQTT_GetSubscribePacketSize( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ &remainingLength,
+ &packetSize,
+ maxPacketSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+
+ fixedBuffer.size = bufferSize;
+
+ /* Make sure success is returned for good case. */
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* test SerializeSubscribe with NULL property buffer. */
+ propBuffer.pBuffer = NULL;
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* test MQTT_SerializeSubscribe subscription options. */
+ subscriptionList.qos = MQTTQoS1;
+ subscriptionList.pTopicFilter = "/example/topic";
+ subscriptionList.topicFilterLength = sizeof( "/example/topic" );
+ subscriptionList.noLocalOption = 1;
+ subscriptionList.retainAsPublishedOption = 1;
+ subscriptionList.retainHandlingOption = retainSendOnSub;
+
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ subscriptionList.qos = MQTTQoS2;
+ subscriptionList.retainHandlingOption = retainDoNotSendonSub;
+
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeSubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+
+void test_MQTT_SerializeSubscribe_NullTopicFilter( void )
+{
+ MQTTSubscribeInfo_t subscriptionList;
+ uint32_t remainingLength = 20;
+ uint8_t buffer[ 100 ];
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = buffer, .size = sizeof( buffer ) };
+ MQTTStatus_t status;
+
+ subscriptionList.pTopicFilter = NULL;
+ subscriptionList.topicFilterLength = 10;
+ status = MQTT_SerializeSubscribe( &subscriptionList, 1, NULL, 1, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ subscriptionList.pTopicFilter = "test";
+ subscriptionList.topicFilterLength = 0;
+ status = MQTT_SerializeSubscribe( &subscriptionList, 1, NULL, 1, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+void test_MQTT_SerializeUnsubscribe_NullTopicFilter( void )
+{
+ MQTTSubscribeInfo_t subscriptionList;
+ uint32_t remainingLength = 20;
+ uint8_t buffer[ 100 ];
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = buffer, .size = sizeof( buffer ) };
+ MQTTStatus_t status;
+
+ subscriptionList.pTopicFilter = NULL;
+ subscriptionList.topicFilterLength = 10;
+ status = MQTT_SerializeUnsubscribe( &subscriptionList, 1, NULL, 1, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ subscriptionList.pTopicFilter = "test";
+ subscriptionList.topicFilterLength = 0;
+ status = MQTT_SerializeUnsubscribe( &subscriptionList, 1, NULL, 1, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Tests that MQTT_SerializeUnsubscribe works as intended.
+ */
+void test_MQTT_SerializeUnsubscribe( void )
+{
+ MQTTSubscribeInfo_t subscriptionList;
+ size_t subscriptionCount = 1;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 33 + 2 * BUFFER_PADDING_LENGTH ];
+ size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
+ uint32_t packetSize = bufferSize;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
+ uint8_t expectedPacket[ 100 ];
+ uint8_t * pIterator = expectedPacket;
+
+ const uint16_t PACKET_ID = 1;
+
+ status = MQTT_SerializeUnsubscribe( NULL,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ 0,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Verify a NULL buffer in the fixed buffer struct fails */
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Restore the fixed buffer. */
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+
+ /* Get correct values of packetsize and remaining length. */
+ memset( &subscriptionList, 0x0, sizeof( subscriptionList ) );
+ subscriptionList.qos = MQTTQoS0;
+ subscriptionList.pTopicFilter = "/example/topic";
+ subscriptionList.topicFilterLength = sizeof( "/example/topic" );
+ subscriptionCount = sizeof( subscriptionList ) / sizeof( MQTTSubscribeInfo_t );
+ status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ &remainingLength,
+ &packetSize,
+ MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+
+ /* Make sure subscription count of zero fails. */
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ 0,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Test if buffer is too small. */
+ fixedBuffer.size = 1;
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+ fixedBuffer.size = bufferSize;
+
+ /* Make sure success it returned for good case. */
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* MQTT UNSUBSCRIBE packet format:
+ * 0xA2 (1 byte)
+ * Remaining length (1-4 bytes)
+ * Packet ID (2 bytes)
+ * Topic filters (series of 2 byte lengths followed by filter) (variable) */
+ *pIterator++ = MQTT_PACKET_TYPE_UNSUBSCRIBE;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
+ *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0;
+ pIterator += encodeStringUT( pIterator, subscriptionList.pTopicFilter, subscriptionList.topicFilterLength );
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+
+ MQTTUserProperty_t userProp;
+ userProp.pKey = "abc";
+ userProp.pValue = "def";
+ userProp.keyLength = 3;
+ userProp.valueLength = 3;
+ MQTTPropAdd_UserProp( &propBuffer, &userProp, NULL );
+
+ status = MQTT_GetUnsubscribePacketSize( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ &remainingLength,
+ &packetSize,
+ MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* Test with null property buffer. */
+ propBuffer.pBuffer = NULL;
+ status = MQTT_SerializeUnsubscribe( &subscriptionList,
+ subscriptionCount,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+}
+/* ========================================================================== */
+
+void test_MQTTV5_suback( void )
+{
+ MQTTStatus_t status;
+ uint8_t * pIndex;
+
+ memset( &properties, 0x00, sizeof( properties ) );
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ uint8_t packetBuffer[ 23 ] =
+ {
+ 0x90, /* Fixed header: SUBACK type (0x90) */
+ 0x14, /* Remaining Length = 20 bytes */
+ 0x00, 0x01, /* Packet Identifier = 1 */
+ 0x11, /* Property Length = 17 bytes */
+ 0x1F, /* Property ID = 0x1F (Reason String) */
+ 0x00, 0x03, /* UTF-8 string length = 3 */
+ 0x61, 0x62, 0x63, /* The string "abc" */
+ 0x26, 0x00, 0x03, 0x61, 0x62, 0x63, 0x00, 0x03, 0x61, 0x62, 0x63,
+ 0x00 /* Payload: Reason code = 0x00 (Success) */
+ };
+
+ MQTTPacketInfo_t subackPacket;
+
+ memset( &subackPacket, 0, sizeof( subackPacket ) );
+ subackPacket.type = MQTT_PACKET_TYPE_SUBACK; /* Should be defined as 0x90 */
+ subackPacket.remainingLength = 21; /* From the fixed header (0x0A) */
+ subackPacket.headerLength = 2; /* Fixed header size in this example */
+ subackPacket.pRemainingData = &packetBuffer[ 2 ];
+ uint16_t packetIdentifier = 0;
+ MQTTReasonCodeInfo_t subackReasonCodes;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ packetBuffer[ 11 ] = 0x00;
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, NULL, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_DeserializeAck( NULL, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_DeserializeAck( &subackPacket, NULL, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ uint8_t packetBufferNoProperties[ 7 ] =
+ {
+ 0x90, /* Fixed header: SUBACK type (0x90) */
+ 4, /* Remaining Length = 4 bytes */
+ 0x00, 0x01, /* Packet Identifier = 1 */
+ 0x00, /* Property Length = 1 byte */
+ 0x00, /* Payload: Reason code = 0x00 (Success) */
+ 0x00
+ };
+
+ memset( &subackPacket, 0, sizeof( subackPacket ) );
+ subackPacket.type = MQTT_PACKET_TYPE_SUBACK; /* Should be defined as 0x90 */
+ subackPacket.remainingLength = 4;
+ subackPacket.headerLength = 2;
+ subackPacket.pRemainingData = &packetBufferNoProperties[ 2 ];
+ packetIdentifier = 0;
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ packetBufferNoProperties[ 5 ] = 0x80; /* Change reason code to 0x01 (Unspecified error) */
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
+
+ /* Invalid Property Length. */
+ subackPacket.remainingLength = 20;
+ pIndex = &packetBufferNoProperties[ 4 ];
+ encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ subackPacket.remainingLength = 4;
+ packetBufferNoProperties[ 4 ] = 0; /* Set property length to 0 bytes */
+ packetBufferNoProperties[ 5 ] = 0x00; /* Set reason code to 0x00 (Success) */
+ status = MQTT_DeserializeAck( &subackPacket, &packetIdentifier, &subackReasonCodes, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+
+void test_MQTTV5_GetUnsubscribePacketSize( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = 0;
+ uint32_t packetSize = 0;
+
+ status = MQTT_GetUnsubscribePacketSize( NULL, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, NULL, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, NULL, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ subscribeInfo.pTopicFilter = TEST_TOPIC_NAME;
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_UINT32( 16U, remainingLength );
+ TEST_ASSERT_EQUAL_UINT32( 18U, packetSize );
+
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 0, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ subscribeInfo.topicFilterLength = 65536;
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+
+ subscribeInfo.topicFilterLength = MQTT_MAX_REMAINING_LENGTH;
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+
+ subscribeInfo.topicFilterLength = TEST_TOPIC_NAME_LENGTH;
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, NULL, &remainingLength, &packetSize, 10 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ MQTTPropBuilder_t propBuffer;
+ propBuffer.pBuffer = NULL;
+ status = MQTT_GetUnsubscribePacketSize( &subscribeInfo, 1, &propBuffer, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+void test_MQTTV5_DeserializeSuback( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ uint16_t packetIdentifier;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buffer[ 50 ] = { 0 };
+
+ memset( &properties, 0x00, sizeof( properties ) );
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+
+ /* Bad remaining length. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
+ mqttPacketInfo.pRemainingData = buffer;
+ mqttPacketInfo.remainingLength = 14;
+ /* Set packet identifier. */
+ buffer[ 0 ] = 0;
+ buffer[ 1 ] = 1;
+ buffer[ 2 ] = 0;
+ buffer[ 3 ] = 0x01;
+ buffer[ 4 ] = 0x02;
+ buffer[ 5 ] = 0x80;
+ buffer[ 6 ] = 0x83;
+ buffer[ 7 ] = 0x87;
+ buffer[ 8 ] = 0x8F;
+ buffer[ 9 ] = 0x91;
+ buffer[ 10 ] = 0x97;
+ buffer[ 11 ] = 0x9E;
+ buffer[ 12 ] = 0xA1;
+ buffer[ 13 ] = 0xA2;
+
+ MQTTReasonCodeInfo_t subackReasonCodes;
+
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ buffer[ 13 ] = 0xA4;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Max Packet Size lesser than suback packet size*/
+ properties.maxPacketSize = 1U;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+
+ /* Invalid Remaining Length*/
+ mqttPacketInfo.remainingLength = 2;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ mqttPacketInfo.remainingLength = 14;
+
+ /* Invalid packet type*/
+ buffer[ 1 ] = 0;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, &packetIdentifier, &subackReasonCodes, &propBuffer, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_incoming_publish2( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ uint16_t packetIdentifier = 1;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buffer[ 100 ] = { 0 };
+ uint8_t * pIndex = NULL;
+
+ buffer[ 0 ] = 0x00;
+ buffer[ 1 ] = 0x04;
+ buffer[ 2 ] = 't', buffer[ 3 ] = 'e', buffer[ 4 ] = 's', buffer[ 5 ] = 't';
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ mqttPacketInfo.pRemainingData = buffer;
+ pIndex = &buffer[ 6 ];
+
+ size_t propertyLength = encodeVariableLengthUT( pIndex, 46 );
+ mqttPacketInfo.remainingLength = 52 + propertyLength;
+ pIndex++;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CONTENT_TYPE_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+
+ MQTTPublishInfo_t publishIn;
+ ( void ) memset( &publishIn, 0x0, sizeof( publishIn ) );
+
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Test with NULL Property Builder. */
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, NULL, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Invalid property length*/
+ buffer[ 6 ] = 100;
+ mqttPacketInfo.remainingLength = 46;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Only packet ID present*/
+ mqttPacketInfo.type = ( MQTT_PACKET_TYPE_PUBLISH | 0x04 );
+ mqttPacketInfo.remainingLength = 9;
+ buffer[ 6 ] = 0x00, buffer[ 7 ] = 0x01, buffer[ 8 ] = 0x00;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* A property is received twice. */
+ buffer[ 6 ] = 12;
+ pIndex = &buffer[ 7 ];
+ mqttPacketInfo.remainingLength = 21;
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* A property is received twice. */
+ pIndex = &buffer[ 7 ];
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* A property is received twice. */
+ pIndex = &buffer[ 7 ];
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* A property is received twice. */
+ pIndex = &buffer[ 7 ];
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* A property is received twice. */
+ pIndex = &buffer[ 7 ];
+ buffer[ 6 ] = 10;
+ mqttPacketInfo.remainingLength = 17;
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid topic alias. */
+ buffer[ 6 ] = 3;
+ pIndex = &buffer[ 7 ];
+ mqttPacketInfo.remainingLength = 10;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ uint16_t topicAliasMax = 1;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, topicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid property type. */
+ buffer[ 6 ] = 5;
+ pIndex = &buffer[ 7 ];
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ mqttPacketInfo.remainingLength = 12;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, topicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Test Incoming Publish with Payload. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ buffer[ 6 ] = 0x00;
+ buffer[ 7 ] = 0x01;
+ mqttPacketInfo.remainingLength = 8;
+
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, NULL, 100, topicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Invalid Property Length. */
+ pIndex = &buffer[ 6 ];
+ mqttPacketInfo.remainingLength = 20;
+ propertyLength = encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, NULL, 100, topicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ buffer[ 6 ] = 10;
+ buffer[ 7 ] = MQTT_SUBSCRIPTION_ID_ID;
+ pIndex = &buffer[ 8 ];
+ encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, topicAliasMax );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_incoming_publish_invalidRemainingLength( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ uint16_t packetIdentifier = 1;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buffer[ 100 ] = { 0 };
+
+ buffer[ 0 ] = 0x00;
+ buffer[ 1 ] = 0x04;
+ buffer[ 2 ] = 't', buffer[ 3 ] = 'e', buffer[ 4 ] = 's', buffer[ 5 ] = 't';
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ mqttPacketInfo.pRemainingData = buffer;
+
+ mqttPacketInfo.remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+
+ MQTTPublishInfo_t publishIn;
+ ( void ) memset( &publishIn, 0x0, sizeof( publishIn ) );
+
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+void test_incoming_publish_withPacketId( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ uint16_t packetIdentifier = 1;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buffer[ 8 ] = { 0 };
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0x2;
+ mqttPacketInfo.pRemainingData = buffer;
+ mqttPacketInfo.remainingLength = 8;
+
+ buffer[ 0 ] = 0x00;
+ buffer[ 1 ] = 0x03;
+ buffer[ 2 ] = 0x61;
+ buffer[ 3 ] = 0x62;
+ buffer[ 4 ] = 0x63;
+ buffer[ 5 ] = 0x00;
+ buffer[ 6 ] = 0x01;
+ buffer[ 7 ] = 0x00;
+
+ MQTTPublishInfo_t publishIn;
+ ( void ) memset( &publishIn, 0x0, sizeof( publishIn ) );
+
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ buffer[ 6 ] = 0x00;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_Invalid_IncomingPublish( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ uint16_t packetIdentifier = 1;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buffer[ 3 ] = { 0 };
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ mqttPacketInfo.pRemainingData = buffer;
+ mqttPacketInfo.remainingLength = 3;
+
+ buffer[ 0 ] = 0x00;
+ buffer[ 1 ] = 0x01;
+ buffer[ 2 ] = 0x61;
+
+ MQTTPublishInfo_t publishIn;
+ ( void ) memset( &publishIn, 0x0, sizeof( publishIn ) );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0x02;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishIn, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+/**
+ * @brief Tests that MQTT_SerializeDisconnect works as intended.
+ */
+void test_MQTT_SerializeDisconnect( void )
+{
+ uint8_t buffer[ 25 + 2 * BUFFER_PADDING_LENGTH ];
+ size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
+ uint32_t packetSize = bufferSize;
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
+ uint8_t expectedPacket[ 10 ] = { 0 };
+ uint8_t * pIterator = expectedPacket;
+ MQTTStatus_t status = MQTTSuccess;
+ uint32_t remainingLength = 0;
+ MQTTPropBuilder_t propBuffer = { 0 };
+ MQTTSuccessFailReasonCode_t reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+
+ /* Buffer size less than disconnect request fails. */
+ fixedBuffer.size = 1;
+ status = MQTT_SerializeDisconnect( NULL, &reasonCode, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+
+ status = MQTT_SerializeDisconnect( &propBuffer, NULL, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* NULL buffer fails. */
+ status = MQTT_SerializeDisconnect( NULL, &reasonCode, remainingLength, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Restore the fixed buffer. */
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+ fixedBuffer.size = bufferSize;
+ status = MQTT_GetDisconnectPacketSize( NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+ /* Good case succeeds. */
+ status = MQTT_SerializeDisconnect( NULL, &reasonCode, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+ *pIterator++ = MQTT_PACKET_TYPE_DISCONNECT;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ *pIterator++ = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ *pIterator = 0; /* Property length is 0 */
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+
+ /* Test with properties. */
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+
+ MQTTPropAdd_SessionExpiry( &propBuffer, 10, NULL );
+ status = MQTT_GetDisconnectPacketSize( &propBuffer,
+ &remainingLength,
+ &packetSize,
+ MQTT_MAX_PACKET_SIZE,
+ &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ /* Make sure buffer has enough space */
+ TEST_ASSERT_GREATER_OR_EQUAL( packetSize, bufferSize );
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+
+ status = MQTT_SerializeDisconnect( &propBuffer, &reasonCode, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+ pIterator = expectedPacket;
+ *pIterator++ = MQTT_PACKET_TYPE_DISCONNECT;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ *pIterator++ = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ *pIterator++ = 5; /* Property length is 2 */
+ *pIterator++ = 0x11; /* Session Expiry ID*/
+ pIterator += 3;
+ *pIterator = 10; /* Session Expiry value */
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+
+ /* test with null property buffer. */
+ propBuffer.pBuffer = NULL;
+ status = MQTT_SerializeDisconnect( &propBuffer, &reasonCode, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* pFixedBuffer->pBuffer is NULL */
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializeDisconnect( &propBuffer, &reasonCode, remainingLength, &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Tests that MQTT_GetPingreqPacketSize works as intended.
+ */
+void test_MQTT_GetPingreqPacketSize( void )
+{
+ MQTTStatus_t status;
+ uint32_t packetSize;
+
+ /* Verify parameters. */
+ status = MQTT_GetPingreqPacketSize( NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Good case succeeds. A PINGREQ is 2 bytes. */
+ status = MQTT_GetPingreqPacketSize( &packetSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 2, packetSize );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePingreq works as intended.
+ */
+void test_MQTT_SerializePingreq( void )
+{
+ uint8_t buffer[ 10 + 2 * BUFFER_PADDING_LENGTH ];
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ] };
+ uint8_t expectedPacket[ 2 ] = { MQTT_PACKET_TYPE_PINGREQ, 0 };
+ MQTTStatus_t status = MQTTSuccess;
+
+ /* Buffer size less than ping request fails. */
+ fixedBuffer.size = 1;
+ status = MQTT_SerializePingreq( &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+
+ /* NULL buffer fails. */
+ status = MQTT_SerializePingreq( NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Verify a NULL buffer in the fixed buffer struct fails */
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializePingreq( &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Restore the fixed buffer. */
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+
+ /* Good case succeeds. */
+ fixedBuffer.size = 2;
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializePingreq( &fixedBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], 2 );
+}
+
+/**
+ * @brief Tests that MQTT_DeserializeAck works as intended with a PINGRESP.
+ */
+void test_MQTT_DeserializeAck_pingresp( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTReasonCodeInfo_t reasonCode;
+
+ properties.maxPacketSize = MQTT_MAX_PACKET_SIZE;
+
+ /* Bad remaining length. */
+ ( void ) memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PINGRESP;
+ mqttPacketInfo.remainingLength = MQTT_PACKET_PINGRESP_REMAINING_LENGTH + 1;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &reasonCode, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Process a valid PINGRESP. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PINGRESP;
+ mqttPacketInfo.remainingLength = MQTT_PACKET_PINGRESP_REMAINING_LENGTH;
+ mqttPacketInfo.pRemainingData = NULL;
+ status = MQTT_DeserializeAck( &mqttPacketInfo, NULL, &reasonCode, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ status = MQTT_DeserializeAck( NULL, NULL, NULL, NULL, &properties );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Tests that MQTT_GetIncomingPacketTypeAndLength works as intended.
+ */
+void test_MQTT_GetIncomingPacketTypeAndLength1( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPacketInfo_t mqttPacket;
+ NetworkContext_t networkContext;
+ uint8_t buffer[ 10 ];
+ uint8_t * bufPtr = buffer;
+
+ /* Dummy network context - pointer to pointer to a buffer. */
+ networkContext.buffer = &bufPtr;
+
+ /* Test a NULL pIncomingPacket parameter. */
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Test a typical happy path case for a CONN ACK packet. */
+ buffer[ 0 ] = 0x20; /* CONN ACK */
+ buffer[ 1 ] = 0x02; /* Remaining length. */
+
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 0x20, mqttPacket.type );
+ TEST_ASSERT_EQUAL_INT( 0x02, mqttPacket.remainingLength );
+
+ /* Remaining length of 128. MQTT uses 7 bits for data and 1 continuation
+ * bit in each byte. Since 128 is 8 bits, it needs 2 bytes. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ buffer[ 1 ] = 0x80; /* LSB: CB=1, value=0x00 */
+ buffer[ 2 ] = 0x01; /* MSB: CB=0, value=0x01 */
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTT_PACKET_TYPE_PUBLISH, mqttPacket.type );
+ TEST_ASSERT_EQUAL_INT( 128, mqttPacket.remainingLength );
+
+ /* Remaining length of 16384. MQTT uses 7 bits for data and 1 continuation
+ * bit in each byte. Since 16384 is 15 bits, it needs 3 bytes. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ buffer[ 1 ] = 0x80; /* LSB : CB=1, value=0x00 */
+ buffer[ 2 ] = 0x80; /* Byte 1: CB=1, value=0x00 */
+ buffer[ 3 ] = 0x01; /* MSB : CB=0, value=0x01 */
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTT_PACKET_TYPE_PUBLISH, mqttPacket.type );
+ TEST_ASSERT_EQUAL_INT( 16384, mqttPacket.remainingLength );
+
+ /* Test with incorrect packet type. */
+ bufPtr = buffer;
+ buffer[ 0 ] = 0x10; /* INVALID */
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test with disconnect packet type. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with invalid remaining length. */
+ bufPtr = buffer;
+ buffer[ 0 ] = 0x20; /* CONN ACK */
+
+ /* To generate invalid remaining length response,
+ * four bytes need to have MSB (or continuation bit, 0x80) set */
+ buffer[ 1 ] = 0xFF;
+ buffer[ 2 ] = 0xFF;
+ buffer[ 3 ] = 0xFF;
+ buffer[ 4 ] = 0xFF;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Check with an encoding that does not conform to the MQTT spec. */
+ bufPtr = buffer;
+ buffer[ 1 ] = 0x80;
+ buffer[ 2 ] = 0x80;
+ buffer[ 3 ] = 0x80;
+ buffer[ 4 ] = 0x00;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Check when network receive fails. */
+ memset( buffer, 0x00, 10 );
+ bufPtr = buffer;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveFailure, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTRecvFailed, status );
+
+ /* Test if no data is available. */
+ bufPtr = buffer;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveNoData, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTNoDataAvailable, status );
+
+ /* Branch coverage for PUBREL. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_PUBREL & 0xF0U;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceive, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Receive type then fail. */
+ bufPtr = buffer;
+ buffer[ 0 ] = MQTT_PACKET_TYPE_PUBREL;
+ status = MQTT_GetIncomingPacketTypeAndLength( mockReceiveSucceedThenFail, &networkContext, &mqttPacket );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+void test_MQTT_SerializePublishHeaderWithoutTopic_BadInputs( void )
+{
+ MQTTPublishInfo_t publishInfo = { 0 };
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( NULL,
+ remainingLength,
+ buffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ MQTT_REMAINING_LENGTH_INVALID,
+ buffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ NULL,
+ &headerSize );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_AllNULL( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set. Except publish flag. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ MQTT_REMAINING_LENGTH_INVALID - 20,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 7U, headerSize );
+ /* No flag should be set. Except publish flag. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( 236, buffer[ 1 ] );
+ TEST_ASSERT_EQUAL( 255, buffer[ 2 ] );
+ TEST_ASSERT_EQUAL( 255, buffer[ 3 ] );
+ TEST_ASSERT_EQUAL( 127, buffer[ 4 ] );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( 0U, buffer[ 5 ] );
+ TEST_ASSERT_EQUAL( 0U, buffer[ 6 ] );
+}
+
+/* ========================================================================== */
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_QoS1( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ publishInfo.qos = MQTTQoS1;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set except QoS1 and publish flag. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 1 ) | 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_QoS2( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ publishInfo.qos = MQTTQoS2;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set except QoS2. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 2 ) | 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_retain( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ publishInfo.retain = true;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set except retain flag. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 0 ) | 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_Duplicate( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ publishInfo.dup = true;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set except dup. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 3 ) | 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ */
+void test_MQTT_SerializePublishHeaderWithoutTopic_VariousFlagsSetTopicLength( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 7 ];
+ MQTTStatus_t status = MQTTSuccess;
+ size_t headerSize = 0;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+
+ publishInfo.qos = MQTTQoS2;
+ publishInfo.dup = true;
+ publishInfo.retain = true;
+ publishInfo.topicNameLength = 20;
+
+ status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
+ remainingLength,
+ buffer,
+ &headerSize );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( headerSize, 4U );
+ /* No flag should be set except QoS2/dup/retain. */
+ TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 2 ) | ( 1U << 3 ) | ( 1U << 0 ) | 0x30 );
+ /* The encoded length must be 0. */
+ TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
+ /* The topic name length should be 0 too. */
+ TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
+ TEST_ASSERT_EQUAL( buffer[ 3 ], 20U );
+}
+
+/**
+ * @brief Tests that MQTT_SerializePublishHeader works as intended.
+ */
+void test_MQTT_SerializePublishHeader( void )
+{
+ MQTTPublishInfo_t publishInfo;
+ uint32_t remainingLength = 0;
+ uint8_t buffer[ 200 + 2 * BUFFER_PADDING_LENGTH ];
+ uint8_t expectedPacket[ 200 ];
+ uint8_t * pIterator;
+ size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
+ uint32_t packetSize = bufferSize;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
+ size_t headerSize = 0;
+
+ const uint16_t PACKET_ID = 1;
+
+ /* Verify bad parameters fail. */
+ memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ publishInfo.pTopicName = TEST_TOPIC_NAME;
+ publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
+ status = MQTT_SerializePublishHeader( NULL,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ NULL,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Verify a NULL buffer in the fixed buffer struct fails */
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Restore the fixed buffer. */
+ fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+
+ /* Empty topic fails. */
+ publishInfo.pTopicName = NULL;
+ publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ publishInfo.pTopicName = TEST_TOPIC_NAME;
+ publishInfo.topicNameLength = 0;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
+
+ /* 0 packet ID for QoS > 0. */
+ publishInfo.qos = MQTTQoS1;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ 0,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Verify that a duplicate flag for Qos 0 fails. */
+ publishInfo.qos = MQTTQoS0;
+ publishInfo.dup = true;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Restore the previous flags for other tests. */
+ publishInfo.qos = MQTTQoS1;
+ publishInfo.dup = false;
+
+ /* Buffer too small. */
+ fixedBuffer.size = 1;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
+ fixedBuffer.size = bufferSize;
+
+ /* Success case. */
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* MQTT PUBLISH packet format:
+ * 0x30 | publish flags (dup, qos, retain) (1 byte)
+ * Remaining length (1-4 bytes)
+ * Topic name length (2 bytes)
+ * Topic name (variable)
+ * Packet ID (if QoS > 0) (1 byte)
+ * Payload (>= 0 bytes) */
+ memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
+ pIterator = expectedPacket;
+ *pIterator++ = MQTT_PACKET_TYPE_PUBLISH | ( publishInfo.qos << 1 );
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ pIterator += encodeStringUT( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
+ *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
+ *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0;
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ publishInfo.qos = MQTTQoS0;
+ publishInfo.pPayload = "test";
+ publishInfo.payloadLength = 4;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ 0,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
+ pIterator = expectedPacket;
+ *pIterator++ = MQTT_PACKET_TYPE_PUBLISH;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ pIterator += encodeStringUT( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
+ *pIterator++ = 0;
+ /* Payload should not be serialized. */
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* Again with QoS2 and dup. */
+ publishInfo.qos = MQTTQoS2;
+ publishInfo.dup = true;
+ status = MQTT_GetPublishPacketSize( &publishInfo, NULL, &remainingLength, &packetSize, MQTT_MAX_PACKET_SIZE );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ padAndResetBuffer( buffer, sizeof( buffer ) );
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ NULL,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
+ pIterator = expectedPacket;
+ /* Set the flags as follows: Dup = 0x8, QoS2 = 0x4, 8 | 4 = 0xC. */
+ *pIterator++ = MQTT_PACKET_TYPE_PUBLISH | 0xC;
+ pIterator += encodeVariableLengthUT( pIterator, remainingLength );
+ pIterator += encodeStringUT( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
+ *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
+ *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
+ *pIterator++ = 0;
+ TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
+ checkBufferOverflow( buffer, sizeof( buffer ) );
+
+ /* test with publish properties */
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+ MQTTPropAdd_MessageExpiry( &propBuffer, 100, NULL );
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* test with null buffer. */
+ propBuffer.pBuffer = NULL;
+ status = MQTT_SerializePublishHeader( &publishInfo,
+ &propBuffer,
+ PACKET_ID,
+ remainingLength,
+ &fixedBuffer,
+ &headerSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+
+/* ========================================================================== */
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_PacketNULL( void )
+{
+ uint8_t pBuffer[ 100 ] = { 0 };
+ size_t index = 0;
+ MQTTStatus_t status;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, NULL );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_BufferNULL( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ size_t index = 0;
+ MQTTStatus_t status;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( NULL, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_IndexNULL( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ] = { 0 };
+ MQTTStatus_t status;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, NULL, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_NoData( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ] = { 0 };
+ size_t index = 0;
+ MQTTStatus_t status;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTNoDataAvailable, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_InvalidData( void )
+{
+ MQTTPacketInfo_t packetInfo = { 0 };
+ uint8_t pBuffer[ 100 ];
+ size_t index = 2;
+ MQTTStatus_t status;
+
+ memset( pBuffer, 0, 100 );
+
+ /* MQTT_PACKET_TYPE_PUBREL without lower nibble set. */
+ pBuffer[ 0 ] = 0x60;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_ValidDataOneByte( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ];
+ size_t index = 1;
+ MQTTStatus_t status;
+
+ memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
+ memset( pBuffer, 0, 100 );
+
+ pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTNeedMoreBytes, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_ValidDataTwoBytes( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ];
+ size_t index = 2;
+ MQTTStatus_t status;
+
+ memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
+ memset( pBuffer, 0, 100 );
+
+ pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ /* 2nd byte is the length. */
+ pBuffer[ 1 ] = 10;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( packetInfo.remainingLength, 10U );
+ TEST_ASSERT_EQUAL( packetInfo.headerLength, 2U );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_InvalidLength( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ];
+ size_t index = 6;
+ MQTTStatus_t status;
+
+ memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
+ memset( pBuffer, 0, 100 );
+
+ pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ /* 2nd byte onward is the length. */
+ pBuffer[ 1 ] = 0xFF;
+ pBuffer[ 2 ] = 0xFF;
+ pBuffer[ 3 ] = 0xFF;
+ /* This byte doesn't terminate the length. */
+ pBuffer[ 4 ] = 0xFF;
+ pBuffer[ 5 ] = 0xFF;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+void test_MQTT_ProcessIncomingPacketTypeAndLength_NonConformingLength( void )
+{
+ MQTTPacketInfo_t packetInfo;
+ uint8_t pBuffer[ 100 ];
+ size_t index = 6;
+ MQTTStatus_t status;
+
+ memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
+ memset( pBuffer, 0, 100 );
+
+ pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ /* 2nd byte onward is the length. */
+ pBuffer[ 1 ] = 0x80;
+ pBuffer[ 2 ] = 0x80;
+ pBuffer[ 3 ] = 0x80;
+ /* This byte doesn't terminate the length. */
+ pBuffer[ 4 ] = 0x00;
+
+ status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+/**
+ * @brief Tests that MQTT_DeserializePublish works as intended.
+ */
+void test_MQTT_DeserializePublish( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo;
+ MQTTPublishInfo_t publishInfo;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buffer[ 100 ];
+ MQTTPropBuilder_t propBuffer = { 0 };
+
+ uint16_t packetIdentifier;
+
+ memset( &mqttPacketInfo, 0x00, sizeof( mqttPacketInfo ) );
+
+ /* Verify parameters. */
+ status = MQTT_DeserializePublish( NULL, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, NULL, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, NULL, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Bad Packet Type. */
+ mqttPacketInfo.type = 0x01;
+ mqttPacketInfo.pRemainingData = buffer;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Incorrect flags. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0xf;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* QoS 0 bad remaining length. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH;
+ mqttPacketInfo.remainingLength = 0;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* QoS 1 bad remaining length. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_PUBLISH | 0x2;
+ mqttPacketInfo.remainingLength = 0;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* QoS 1 invalid packet identifier. */
+ mqttPacketInfo.remainingLength = 5;
+ buffer[ 0 ] = 0;
+ buffer[ 1 ] = 1;
+ buffer[ 2 ] = ( uint8_t ) 'a';
+ buffer[ 3 ] = 0;
+ buffer[ 4 ] = 0;
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 100, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid max packet size*/
+ status = MQTT_DeserializePublish( &mqttPacketInfo, &packetIdentifier, &publishInfo, &propBuffer, 1, 100 );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+void test_serializeHeaders( void )
+{
+ uint8_t buffer[ 4 ];
+
+ serializeSubscribeHeader( 3, buffer, 1 );
+ TEST_ASSERT_EQUAL( buffer[ 0 ], MQTT_PACKET_TYPE_SUBSCRIBE );
+ serializeUnsubscribeHeader( 3, buffer, 1 );
+ TEST_ASSERT_EQUAL( buffer[ 0 ], MQTT_PACKET_TYPE_UNSUBSCRIBE );
+ uint8_t buf[ 22 ];
+ MQTTConnectInfo_t pConnectInfo;
+ pConnectInfo.cleanSession = true;
+ pConnectInfo.pUserName = "abc";
+ pConnectInfo.pPassword = "def";
+ pConnectInfo.keepAliveSeconds = 100;
+ MQTTPublishInfo_t pWillInfo;
+ pWillInfo.qos = MQTTQoS1;
+ pWillInfo.retain = true;
+ serializeConnectFixedHeader( buf, &pConnectInfo, &pWillInfo, 20 );
+ pWillInfo.qos = MQTTQoS2;
+ serializeConnectFixedHeader( buf, &pConnectInfo, &pWillInfo, 20 );
+}
+
+void test_OptionalProperties( void )
+{
+ MQTTStatus_t mqttStatus = MQTTSuccess;
+ MQTTPropBuilder_t propBuilder;
+ MQTTPropBuilder_t prop1;
+
+ prop1.pBuffer = NULL;
+ uint8_t buf[ 100 ];
+ size_t bufLength = sizeof( buf );
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ mqttStatus = MQTTPropAdd_SubscriptionId( &propBuilder, 2, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_SubscriptionId( &propBuilder, 2, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_SubscriptionId( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SubscriptionId( NULL, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SubscriptionId( &prop1, 2, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ MQTTUserProperty_t userProperty;
+ memset( &userProperty, 0x0, sizeof( userProperty ) );
+ userProperty.pKey = "abc";
+ userProperty.pValue = "def";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 3;
+ mqttStatus = MQTTPropAdd_UserProp( &( propBuilder ), &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_UserProp( NULL, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_UserProp( &( propBuilder ), NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_UserProp( &prop1, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ userProperty.pKey = NULL;
+ mqttStatus = MQTTPropAdd_UserProp( &propBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ userProperty.pKey = "abc";
+ userProperty.pValue = NULL;
+ mqttStatus = MQTTPropAdd_UserProp( &propBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ userProperty.pValue = "def";
+ userProperty.keyLength = 0;
+ mqttStatus = MQTTPropAdd_UserProp( &propBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 0;
+ mqttStatus = MQTTPropAdd_UserProp( &propBuilder, &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SessionExpiry( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SessionExpiry( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SessionExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SessionExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( &( propBuilder ), 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MaxPacketSize( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_MaxPacketSize( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_MaxPacketSize( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MaxPacketSize( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MaxPacketSize( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_TopicAliasMax( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAliasMax( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAliasMax( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAliasMax( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_RequestRespInfo( NULL, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestRespInfo( &prop1, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestRespInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ propBuilder.fieldSet = 0;
+ mqttStatus = MQTTPropAdd_RequestRespInfo( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestRespInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_RequestProbInfo( NULL, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestProbInfo( &prop1, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestProbInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ propBuilder.fieldSet = 0;
+ mqttStatus = MQTTPropAdd_RequestProbInfo( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_RequestProbInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test Auth Data before Auth Method. */
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_AuthMethod( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( NULL, "abc", 65536, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( &prop1, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ uint8_t buf1[ 65539 ];
+ int8_t buf2[ 65539 ];
+ memset( buf2, 0xAA, sizeof( buf2 ) );
+ propBuilder.pBuffer = buf1;
+ propBuilder.bufferLength = 65539;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, ( const char * ) buf2, 65535, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_AuthData( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder, NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder, "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthData( &prop1, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_PayloadFormat( NULL, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_PayloadFormat( &prop1, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_PayloadFormat( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ propBuilder.fieldSet = 0;
+ mqttStatus = MQTTPropAdd_PayloadFormat( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_PayloadFormat( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MessageExpiry( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_MessageExpiry( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_MessageExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_MessageExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_TopicAlias( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAlias( &prop1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAlias( &propBuilder, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAlias( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_TopicAlias( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ResponseTopic( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &prop1, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc/#", 5, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc/+/def", 9, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_CorrelationData( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_CorrelationData( &( prop1 ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ContentType( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ContentType( &( prop1 ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ContentType( &( propBuilder ), NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ContentType( &( propBuilder ), "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ContentType( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_ContentType( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReasonString( NULL, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ReasonString( &( prop1 ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ReasonString( &( propBuilder ), NULL, 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ReasonString( &( propBuilder ), "abc", 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_ReasonString( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_ReasonString( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_WillDelayInterval( NULL, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_WillDelayInterval( &( prop1 ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ mqttStatus = MQTTPropAdd_WillDelayInterval( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTTPropAdd_WillDelayInterval( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+}
+
+void test_MQTTPropAdd_NoMemory( void )
+{
+ MQTTStatus_t mqttStatus = MQTTSuccess;
+ MQTTPropBuilder_t propBuilder, propBuilder1;
+ uint8_t buf[ 1 ];
+ size_t bufLength = sizeof( buf );
+
+ uint8_t biggerBuf[ 10 ];
+ size_t biggerBufLen = sizeof( biggerBuf );
+
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ propBuilder1.pBuffer = biggerBuf;
+ propBuilder1.bufferLength = biggerBufLen;
+ propBuilder1.currentIndex = 0;
+ propBuilder1.fieldSet = 0;
+
+ mqttStatus = MQTTPropAdd_ReasonString( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ContentType( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_CorrelationData( &( propBuilder ), "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ResponseTopic( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_TopicAlias( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MessageExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_PayloadFormat( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ /* Restrict the buffer size. */
+ propBuilder1.bufferLength = 7;
+ mqttStatus = MQTTPropAdd_AuthMethod( &propBuilder1, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+ /* CoreMQTT requires that we add auth method before we try and add auth data. */
+ mqttStatus = MQTTPropAdd_AuthData( &propBuilder1, "abc", 3, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_RequestProbInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_RequestRespInfo( &propBuilder, 1, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_TopicAliasMax( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_MaxPacketSize( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_ReceiveMax( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SessionExpiry( &propBuilder, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_WillDelayInterval( &( propBuilder ), 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ MQTTUserProperty_t userProperty;
+ memset( &userProperty, 0x0, sizeof( userProperty ) );
+ userProperty.pKey = "abc";
+ userProperty.pValue = "def";
+ userProperty.keyLength = 3;
+ userProperty.valueLength = 3;
+ mqttStatus = MQTTPropAdd_UserProp( &( propBuilder ), &userProperty, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+
+ mqttStatus = MQTTPropAdd_SubscriptionId( &propBuilder, 2, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTNoMemory, mqttStatus );
+}
+void test_updateContextWithConnectProps( void )
+{
+ MQTTStatus_t mqttStatus = MQTTSuccess;
+ MQTTPropBuilder_t propBuilder;
+ uint8_t buffer[ 50 ];
+ MQTTConnectionProperties_t connectProps;
+ size_t bufLength = sizeof( buffer );
+
+ propBuilder.pBuffer = buffer;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ mqttStatus = updateContextWithConnectProps( &propBuilder, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ uint8_t * pIndex = buffer;
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_REQUEST_PROBLEM_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_REQUEST_RESPONSE_ID );
+ pIndex = serializeutf_8pair( pIndex );
+
+ propBuilder.currentIndex = 27;
+ propBuilder.currentIndex += 13;
+ mqttStatus = updateContextWithConnectProps( &propBuilder, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ mqttStatus = updateContextWithConnectProps( NULL, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = updateContextWithConnectProps( &propBuilder, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ propBuilder.pBuffer = NULL;
+ mqttStatus = updateContextWithConnectProps( &propBuilder, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ propBuilder.pBuffer = buffer;
+ propBuilder.currentIndex = 5;
+ mqttStatus = updateContextWithConnectProps( &propBuilder, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, mqttStatus );
+
+ propBuilder.pBuffer = pIndex;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuilder.currentIndex = 10;
+ mqttStatus = updateContextWithConnectProps( &propBuilder, &connectProps );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+}
+
+void test_MQTT_SerializeAck( void )
+{
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 50 ];
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = sizeof( buf );
+
+ MQTTStatus_t status = MQTTSuccess;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 100, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTSuccess );
+
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 0, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTBadParameter );
+
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_SUBACK, 100, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTBadParameter );
+
+ status = MQTT_SerializeAck( NULL, MQTT_PACKET_TYPE_PUBACK, 100, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTBadParameter );
+
+ fixedBuffer.pBuffer = NULL;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 100, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTBadParameter );
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 1;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 100, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( status, MQTTNoMemory );
+}
+
+void test_MQTTV5_SerializeDisconnect( void )
+{
+ uint8_t buf[ 10 ];
+
+ serializeDisconnectFixed( buf, 0x00, 10 );
+ TEST_ASSERT_EQUAL( buf[ 0 ], MQTT_PACKET_TYPE_DISCONNECT );
+
+ serializeAckFixed( buf, MQTT_PACKET_TYPE_SUBACK, 10, 10, 0x00 );
+ TEST_ASSERT_EQUAL( buf[ 0 ], MQTT_PACKET_TYPE_SUBACK );
+}
+
+void test_validatePublishProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint16_t serverTopicAliasMax;
+ uint16_t topicAlias;
+ MQTTPropBuilder_t propBuilder;
+ uint8_t buffer[ 50 ];
+ size_t bufLength = sizeof( buffer );
+
+ propBuilder.pBuffer = buffer;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ propBuilder.fieldSet = 0;
+
+ status = MQTT_ValidatePublishProperties( 1, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ propBuilder.currentIndex = 0;
+ status = MQTT_ValidatePublishProperties( 1, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ uint8_t * pIndex = buffer;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ propBuilder.currentIndex = 3;
+
+ /* Invalid Topic Alias. */
+ serverTopicAliasMax = 2;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ serverTopicAliasMax = 300;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Property length field less than the actual length of the property. */
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+ propBuilder.currentIndex = 3;
+
+ pIndex = buffer;
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ propBuilder.currentIndex = 7;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
+
+void test_validateSubscribeProperties( void )
+{
+ uint8_t isSubIdAvailable = 0;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuilder;
+ uint8_t buffer[ 50 ];
+ size_t bufLength = sizeof( buffer );
+
+ propBuilder.pBuffer = NULL;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 0;
+ propBuilder.fieldSet = 0;
+
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ propBuilder.pBuffer = buffer;
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Subscription Id not available is set in the connack, but Subscription Id is sent. */
+ uint8_t * pIndex = buffer;
+ *pIndex = MQTT_SUBSCRIPTION_ID_ID;
+ pIndex++;
+ *pIndex = 2;
+
+ propBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Subscription Id is available. */
+ isSubIdAvailable = 1;
+ status = MQTT_ValidateSubscribeProperties( isSubIdAvailable, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Validating user properties. */
+ pIndex = buffer;
+ pIndex = serializeutf_8pair( pIndex );
+ propBuilder.currentIndex += 11;
+ status = MQTT_ValidateSubscribeProperties( 1, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /* Invalid property sent. */
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuilder.currentIndex += 2;
+ status = MQTT_ValidateSubscribeProperties( 1, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Invalid Subscription Id, exceeding 4 bytes. */
+ pIndex = buffer;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ encodeVariableLengthUT( pIndex, 20971556356235 );
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateSubscribeProperties( 1, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ /* Invalid Subscription Id with value 0. */
+ pIndex = buffer;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ encodeVariableLengthUT( pIndex, 0 );
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateSubscribeProperties( 1, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Invalid Subscription Id - included twice */
+ pIndex = buffer;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ encodeVariableLengthUT( pIndex, 10 );
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ encodeVariableLengthUT( pIndex, 10 );
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateSubscribeProperties( 1, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+void test_getProps( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuffer;
+ MQTTPropBuilder_t propBuffer1;
+
+ propBuffer1.pBuffer = NULL;
+ propBuffer1.bufferLength = 0;
+ propBuffer1.currentIndex = 0;
+ propBuffer1.fieldSet = 0;
+
+ uint8_t buffer[ 500 ] = { 0 };
+ size_t bufLength = 500;
+
+ propBuffer.pBuffer = buffer;
+ propBuffer.bufferLength = bufLength;
+ propBuffer.currentIndex = bufLength;
+ propBuffer.fieldSet = 0;
+
+ uint8_t * pIndex = buffer;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CONTENT_TYPE_ID );
+ *pIndex = MQTT_SUBSCRIPTION_ID_ID;
+ pIndex++;
+ *pIndex = 2;
+ pIndex++;
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_MAX_QOS_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_RETAIN_AVAILABLE_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_ASSIGNED_CLIENT_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_WILDCARD_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_SUB_AVAILABLE_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_SERVER_REF_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_SHARED_SUB_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_SERVER_KEEP_ALIVE_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_INFO_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+
+ size_t propCurrentIndex = 0U;
+ uint16_t topicAlias;
+ uint8_t payloadFormat;
+ const char * pResponseTopic;
+ size_t responseTopicLength;
+ const char * correlationData;
+ size_t correlationLength;
+ uint32_t messageExpiry;
+ const char * pContentType;
+ size_t contentTypeLength;
+ uint32_t subscriptionId;
+ uint32_t sessionExpiry;
+ uint16_t aliasMax;
+ uint16_t receiveMax;
+ uint8_t maxQoS;
+ uint8_t retainAvailable;
+ uint32_t maxPacketSize;
+ const char * pClientId;
+ size_t clientIdLength;
+ uint8_t wildcard;
+ uint8_t subAvailable;
+ uint8_t propertyId;
+ const char * pReasonString;
+ size_t reasonStringLength;
+ uint8_t sharedSubAvailable;
+ uint16_t serverKeepAlive;
+ const char * pResponseInfo;
+ size_t responseInfoLength;
+ const char * pAuthMethod;
+ size_t authMethodLength;
+ const char * pAuthData;
+ size_t authDataLength;
+ MQTTUserProperty_t userProp;
+ size_t counter = 0U;
+
+ ( void ) counter;
+ status = MQTT_GetNextPropertyType( NULL, &propCurrentIndex, &propertyId );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_GetNextPropertyType( &propBuffer1, &propCurrentIndex, &propertyId );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, &propertyId );
+ counter++;
+
+ while( status == MQTTSuccess )
+ {
+ switch( propertyId )
+ {
+ case MQTT_TOPIC_ALIAS_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAlias( NULL, &propCurrentIndex, &topicAlias ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAlias( &propBuffer1, &propCurrentIndex, &topicAlias ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAlias( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_TopicAlias( &propBuffer, &propCurrentIndex, &topicAlias ) );
+ break;
+
+ case MQTT_PAYLOAD_FORMAT_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_PayloadFormatIndicator( NULL, &propCurrentIndex, &payloadFormat ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_PayloadFormatIndicator( &propBuffer1, &propCurrentIndex, &payloadFormat ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_PayloadFormatIndicator( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_PayloadFormatIndicator( &propBuffer, &propCurrentIndex, &payloadFormat ) );
+ break;
+
+ case MQTT_RESPONSE_TOPIC_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( NULL, &propCurrentIndex, &pResponseTopic, &responseTopicLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( &propBuffer1, &propCurrentIndex, &pResponseTopic, &responseTopicLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( &propBuffer, &propCurrentIndex, NULL, &responseTopicLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( &propBuffer, &propCurrentIndex, &pResponseTopic, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ResponseTopic( &propBuffer, &propCurrentIndex, &pResponseTopic, &responseTopicLength ) );
+
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( &propBuffer, &propCurrentIndex, &pResponseTopic, &responseTopicLength ) );
+
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseTopic( &propBuffer, &propCurrentIndex, &pResponseTopic, &responseTopicLength ) );
+ break;
+
+ case MQTT_CORRELATION_DATA_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( NULL, &propCurrentIndex, &correlationData, &correlationLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( &propBuffer1, &propCurrentIndex, &correlationData, &correlationLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( &propBuffer, &propCurrentIndex, NULL, &correlationLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( &propBuffer, &propCurrentIndex, &correlationData, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_CorrelationData( &propBuffer, &propCurrentIndex, &correlationData, &correlationLength ) );
+
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( &propBuffer, &propCurrentIndex, &correlationData, &correlationLength ) );
+
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_CorrelationData( &propBuffer, &propCurrentIndex, &correlationData, &correlationLength ) );
+ break;
+
+ case MQTT_MSG_EXPIRY_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MessageExpiryInterval( NULL, &propCurrentIndex, &messageExpiry ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MessageExpiryInterval( &propBuffer1, &propCurrentIndex, &messageExpiry ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MessageExpiryInterval( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_MessageExpiryInterval( &propBuffer, &propCurrentIndex, &messageExpiry ) );
+ break;
+
+ case MQTT_CONTENT_TYPE_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ContentType( NULL, &propCurrentIndex, &pContentType, &contentTypeLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ContentType( &propBuffer1, &propCurrentIndex, &pContentType, &contentTypeLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ContentType( &propBuffer, &propCurrentIndex, NULL, &contentTypeLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ContentType( &propBuffer, &propCurrentIndex, &pContentType, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ContentType( &propBuffer, &propCurrentIndex, &pContentType, &contentTypeLength ) );
+ break;
+
+ case MQTT_SUBSCRIPTION_ID_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubscriptionId( NULL, &propCurrentIndex, &subscriptionId ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubscriptionId( &propBuffer1, &propCurrentIndex, &subscriptionId ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubscriptionId( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_SubscriptionId( &propBuffer, &propCurrentIndex, &subscriptionId ) );
+ break;
+
+ case MQTT_SESSION_EXPIRY_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SessionExpiry( NULL, &propCurrentIndex, &sessionExpiry ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SessionExpiry( &propBuffer1, &propCurrentIndex, &sessionExpiry ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SessionExpiry( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_SessionExpiry( &propBuffer, &propCurrentIndex, &sessionExpiry ) );
+ break;
+
+ case MQTT_TOPIC_ALIAS_MAX_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAliasMax( NULL, &propCurrentIndex, &aliasMax ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAliasMax( &propBuffer1, &propCurrentIndex, &aliasMax ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_TopicAliasMax( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_TopicAliasMax( &propBuffer, &propCurrentIndex, &aliasMax ) );
+ break;
+
+ case MQTT_RECEIVE_MAX_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReceiveMax( NULL, &propCurrentIndex, &receiveMax ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReceiveMax( &propBuffer1, &propCurrentIndex, &receiveMax ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReceiveMax( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ReceiveMax( &propBuffer, &propCurrentIndex, &receiveMax ) );
+ break;
+
+ case MQTT_MAX_QOS_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxQos( NULL, &propCurrentIndex, &maxQoS ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxQos( &propBuffer1, &propCurrentIndex, &maxQoS ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxQos( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_MaxQos( &propBuffer, &propCurrentIndex, &maxQoS ) );
+ break;
+
+ case MQTT_RETAIN_AVAILABLE_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_RetainAvailable( NULL, &propCurrentIndex, &retainAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_RetainAvailable( &propBuffer1, &propCurrentIndex, &retainAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_RetainAvailable( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_RetainAvailable( &propBuffer, &propCurrentIndex, &retainAvailable ) );
+ break;
+
+ case MQTT_MAX_PACKET_SIZE_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxPacketSize( NULL, &propCurrentIndex, &maxPacketSize ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxPacketSize( &propBuffer1, &propCurrentIndex, &maxPacketSize ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_MaxPacketSize( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_MaxPacketSize( &propBuffer, &propCurrentIndex, &maxPacketSize ) );
+ break;
+
+ case MQTT_ASSIGNED_CLIENT_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AssignedClientId( NULL, &propCurrentIndex, &pClientId, &clientIdLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AssignedClientId( &propBuffer1, &propCurrentIndex, &pClientId, &clientIdLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AssignedClientId( &propBuffer, &propCurrentIndex, NULL, &clientIdLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AssignedClientId( &propBuffer, &propCurrentIndex, &pClientId, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_AssignedClientId( &propBuffer, &propCurrentIndex, &pClientId, &clientIdLength ) );
+ break;
+
+ case MQTT_WILDCARD_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_WildcardId( NULL, &propCurrentIndex, &wildcard ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_WildcardId( &propBuffer1, &propCurrentIndex, &wildcard ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_WildcardId( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_WildcardId( &propBuffer, &propCurrentIndex, &wildcard ) );
+ break;
+
+ case MQTT_SUB_AVAILABLE_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubsIdAvailable( NULL, &propCurrentIndex, &subAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubsIdAvailable( &propBuffer1, &propCurrentIndex, &subAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SubsIdAvailable( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_SubsIdAvailable( &propBuffer, &propCurrentIndex, &subAvailable ) );
+ break;
+
+ case MQTT_USER_PROPERTY_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_UserProp( NULL, &propCurrentIndex, &userProp ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_UserProp( &propBuffer1, &propCurrentIndex, &userProp ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_UserProp( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_UserProp( &propBuffer, &propCurrentIndex, &userProp ) );
+ break;
+
+ case MQTT_REASON_STRING_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReasonString( NULL, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReasonString( &propBuffer1, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReasonString( &propBuffer, &propCurrentIndex, NULL, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ReasonString( &propBuffer, &propCurrentIndex, &pReasonString, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ReasonString( &propBuffer, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ break;
+
+ case MQTT_SERVER_REF_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerRef( NULL, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerRef( &propBuffer1, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerRef( &propBuffer, &propCurrentIndex, NULL, &reasonStringLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerRef( &propBuffer, &propCurrentIndex, &pReasonString, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ServerRef( &propBuffer, &propCurrentIndex, &pReasonString, &reasonStringLength ) );
+ break;
+
+ case MQTT_SHARED_SUB_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SharedSubAvailable( NULL, &propCurrentIndex, &sharedSubAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SharedSubAvailable( &propBuffer1, &propCurrentIndex, &sharedSubAvailable ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_SharedSubAvailable( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_SharedSubAvailable( &propBuffer, &propCurrentIndex, &sharedSubAvailable ) );
+ break;
+
+ case MQTT_SERVER_KEEP_ALIVE_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerKeepAlive( NULL, &propCurrentIndex, &serverKeepAlive ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerKeepAlive( &propBuffer1, &propCurrentIndex, &serverKeepAlive ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ServerKeepAlive( &propBuffer, &propCurrentIndex, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ServerKeepAlive( &propBuffer, &propCurrentIndex, &serverKeepAlive ) );
+ break;
+
+ case MQTT_RESPONSE_INFO_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseInfo( NULL, &propCurrentIndex, &pResponseInfo, &responseInfoLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseInfo( &propBuffer1, &propCurrentIndex, &pResponseInfo, &responseInfoLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseInfo( &propBuffer, &propCurrentIndex, NULL, &responseInfoLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_ResponseInfo( &propBuffer, &propCurrentIndex, &pResponseInfo, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_ResponseInfo( &propBuffer, &propCurrentIndex, &pResponseInfo, &responseInfoLength ) );
+ break;
+
+ case MQTT_AUTH_METHOD_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthMethod( NULL, &propCurrentIndex, &pAuthMethod, &authMethodLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthMethod( &propBuffer1, &propCurrentIndex, &pAuthMethod, &authMethodLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthMethod( &propBuffer, &propCurrentIndex, NULL, &authMethodLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthMethod( &propBuffer, &propCurrentIndex, &pAuthMethod, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_AuthMethod( &propBuffer, &propCurrentIndex, &pAuthMethod, &authMethodLength ) );
+ break;
+
+ case MQTT_AUTH_DATA_ID:
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthData( NULL, &propCurrentIndex, &pAuthData, &authDataLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthData( &propBuffer1, &propCurrentIndex, &pAuthData, &authDataLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthData( &propBuffer, &propCurrentIndex, NULL, &authDataLength ) );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, MQTTPropGet_AuthData( &propBuffer, &propCurrentIndex, &pAuthData, NULL ) );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, MQTTPropGet_AuthData( &propBuffer, &propCurrentIndex, &pAuthData, &authDataLength ) );
+ break;
+
+ default:
+ break;
+ }
+
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, &propertyId );
+ }
+
+ propCurrentIndex = 100;
+ propBuffer.currentIndex = 100;
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, &propertyId );
+ TEST_ASSERT_EQUAL_INT( MQTTEndOfProperties, status );
+}
+
+void test_getProps_decodeFailure( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t propBuffer;
+ uint16_t twoByteProperty;
+ uint8_t oneByteProperty;
+ uint8_t propertyId;
+ uint32_t messageExpiry;
+ uint32_t sessionExpiry;
+ uint32_t maxPacketSize;
+ const char * string;
+ size_t stringLength;
+ MQTTUserProperty_t userProp;
+ size_t propCurrentIndex = 0U;
+
+ uint8_t buffer[ 500 ] = { 0 };
+ size_t bufLength = 500;
+
+ propBuffer.pBuffer = buffer;
+ propBuffer.bufferLength = bufLength;
+ propBuffer.currentIndex = 0;
+ propBuffer.fieldSet = 0;
+
+ uint8_t * pIndex = buffer;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuffer.currentIndex = 2;
+
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, &propertyId );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ status = MQTTPropGet_TopicAlias( &propBuffer, &propCurrentIndex, &twoByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ propBuffer.currentIndex = 4;
+ propCurrentIndex = 3;
+ status = MQTT_GetNextPropertyType( &propBuffer, &propCurrentIndex, &propertyId );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ status = MQTTPropGet_PayloadFormatIndicator( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+
+ status = MQTTPropGet_MessageExpiryInterval( &propBuffer, &propCurrentIndex, &messageExpiry );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ContentType( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_SessionExpiry( &propBuffer, &propCurrentIndex, &sessionExpiry );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_TopicAliasMax( &propBuffer, &propCurrentIndex, &twoByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ReceiveMax( &propBuffer, &propCurrentIndex, &twoByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_MaxQos( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_RetainAvailable( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_MaxPacketSize( &propBuffer, &propCurrentIndex, &maxPacketSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_AssignedClientId( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_WildcardId( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_SubsIdAvailable( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_UserProp( &propBuffer, &propCurrentIndex, &userProp );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ReasonString( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ServerRef( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_SharedSubAvailable( &propBuffer, &propCurrentIndex, &oneByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ServerKeepAlive( &propBuffer, &propCurrentIndex, &twoByteProperty );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_ResponseInfo( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_AuthMethod( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ status = MQTTPropGet_AuthData( &propBuffer, &propCurrentIndex, &string, &stringLength );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ uint32_t subId;
+ pIndex = buffer;
+ encodeVariableLengthUT( pIndex, 20971556356235 );
+ status = MQTTPropGet_SubscriptionId( &propBuffer, &propCurrentIndex, &subId );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+/* ================== Testing MQTT_UpdateDuplicatePublishFlag ===================== */
+
+/**
+ * @brief Call MQTT_UpdateDuplicatePublishFlag using a NULL pHeader and a header that does
+ * not come from a publish packet, in order to receive MQTTBadParameter errors.
+ */
+void test_MQTT_UpdateDuplicatePublishFlag_Invalid_Params()
+{
+ MQTTStatus_t mqttStatus = MQTTSuccess;
+ uint8_t pHeader = MQTT_PACKET_TYPE_SUBSCRIBE;
+
+ /* Test NULL pHeader. */
+ mqttStatus = MQTT_UpdateDuplicatePublishFlag( NULL, true );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ /* Test a non-publish header. */
+ mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, true );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
+/**
+ * @brief This method calls MQTT_UpdateDuplicatePublishFlag successfully in order to
+ * get full coverage on the method.
+ */
+void test_MQTT_UpdateDuplicatePublishFlag_Happy_Path()
+{
+ MQTTStatus_t mqttStatus = MQTTSuccess;
+ uint8_t pHeader = MQTT_PACKET_TYPE_PUBLISH;
+
+ /* Test to set the flag. */
+ mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, true );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ TEST_ASSERT_NOT_EQUAL_INT( ( pHeader ) & ( 0x01U << ( 3 ) ), 0 );
+
+ /* Test to clear the flag. */
+ mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, false );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ TEST_ASSERT_EQUAL_INT( ( pHeader ) & ( 0x01U << ( 3 ) ), 0 );
+}
+
+/* ========================================================================== */
+
+void test_ValidatePublishProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint16_t topicAlias;
+ uint16_t serverTopicAliasMax = 10;
+
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, NULL, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ MQTTPropBuilder_t propBuilder = { 0 };
+ propBuilder.pBuffer = NULL;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ uint8_t buf[ 50 ];
+ propBuilder.pBuffer = buf;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ uint8_t * pIndex = buf;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ propBuilder.currentIndex = 20;
+ propBuilder.bufferLength = 50;
+
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid property sent. */
+ pIndex = serializeuint_8( pIndex, MQTT_REQUEST_PROBLEM_ID );
+ propBuilder.currentIndex += 2;
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid property length. */
+ pIndex = buf;
+ propBuilder.currentIndex = 1;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ status = MQTT_ValidatePublishProperties( serverTopicAliasMax, &propBuilder, &topicAlias );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+void test_ValidateDisconnectProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ status = MQTT_ValidateDisconnectProperties( 0, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ MQTTPropBuilder_t propBuffer;
+ propBuffer.pBuffer = NULL;
+ status = MQTT_ValidateDisconnectProperties( 0, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = 25;
+
+ uint8_t * pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_ID );
+
+ status = MQTT_ValidateDisconnectProperties( 10, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Disconnect Session Expiry non-zero while Connect Session Expiry was zero. */
+ status = MQTT_ValidateDisconnectProperties( 0, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid property is sent in the disconnect. */
+ propBuffer.currentIndex = 28;
+ status = MQTT_ValidateDisconnectProperties( 10, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid property length. */
+ propBuffer.currentIndex = 2;
+ status = MQTT_ValidateDisconnectProperties( 10, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ buf[ 0 ] = MQTT_SESSION_EXPIRY_ID;
+ buf[ 1 ] = 0, buf[ 2 ] = 0, buf[ 3 ] = 0, buf[ 4 ] = 0;
+ propBuffer.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_ValidateDisconnectProperties( 0, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ buf[ 0 ] = MQTT_SESSION_EXPIRY_ID;
+ buf[ 1 ] = 0, buf[ 2 ] = 0, buf[ 3 ] = 0, buf[ 4 ] = 0;
+ propBuffer.currentIndex = 5;
+ status = MQTT_ValidateDisconnectProperties( 0, &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
+
+void test_ValidateUnsubscribeProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ status = MQTT_ValidateUnsubscribeProperties( NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ MQTTPropBuilder_t propBuffer = { 0 };
+ propBuffer.pBuffer = NULL;
+ status = MQTT_ValidateUnsubscribeProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+
+ uint8_t * pIndex = buf;
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+
+ /* Invalid property length. */
+ propBuffer.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_ValidateUnsubscribeProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ propBuffer.currentIndex = 13;
+ status = MQTT_ValidateUnsubscribeProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.currentIndex = 18;
+ /* Invalid property send in the unsubscribe. */
+ status = MQTT_ValidateUnsubscribeProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_ValidateWillProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ status = MQTT_ValidateWillProperties( NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ MQTTPropBuilder_t propBuffer;
+ propBuffer.pBuffer = NULL;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ uint8_t buf[ 50 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ propBuffer.currentIndex = 32;
+
+ uint8_t * pIndex = buf;
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_WILL_DELAY_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CONTENT_TYPE_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.currentIndex = 37;
+ /* Invalid property sent in LWT. */
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_WILL_DELAY_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_WILL_DELAY_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 32;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 32;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 2;
+ buf[ 1 ] = 0;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 2;
+ buf[ 1 ] = 1;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ pIndex = buf;
+ pIndex = serializeuint_8( pIndex, MQTT_PAYLOAD_FORMAT_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 2;
+ buf[ 1 ] = 2;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* MQTT_MSG_EXPIRY_ID checks. */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 10;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_CONTENT_TYPE_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CONTENT_TYPE_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 15;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 16;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_RESPONSE_TOPIC_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 7;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 15;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_CORRELATION_DATA_ID );
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 7;
+ status = MQTT_ValidateWillProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
+
+void test_ValidatePublishAckProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buf[ 50 ];
+
+ status = MQTT_ValidatePublishAckProperties( NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ MQTTPropBuilder_t propBuffer = { 0 };
+ propBuffer.pBuffer = buf;
+ propBuffer.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_ValidatePublishAckProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ propBuffer.pBuffer = NULL;
+ propBuffer.currentIndex = 0;
+ status = MQTT_ValidatePublishAckProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = 50;
+ propBuffer.currentIndex = 20;
+
+ uint8_t * pIndex = buf;
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeutf_8( pIndex, MQTT_REASON_STRING_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MSG_EXPIRY_ID );
+
+ status = MQTT_ValidatePublishAckProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ propBuffer.currentIndex = 25;
+
+ status = MQTT_ValidatePublishAckProperties( &propBuffer );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_Mqtt_PropertyBuilder_Init( void )
+{
+ MQTTPropBuilder_t ackPropsBuilder;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTStatus_t mqttStatus;
+
+ mqttStatus = MQTTPropertyBuilder_Init( &( ackPropsBuilder ), ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTTPropertyBuilder_Init( &( ackPropsBuilder ), ackPropsBuf, MQTT_REMAINING_LENGTH_INVALID );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropertyBuilder_Init( NULL, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropertyBuilder_Init( &( ackPropsBuilder ), NULL, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ mqttStatus = MQTTPropertyBuilder_Init( &( ackPropsBuilder ), ackPropsBuf, 0 );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
+void test_decodeSubackPropertyLength( void )
+{
+ uint32_t propertyLength = 0;
+ MQTTStatus_t status;
+ uint8_t buffer[ 10 ] = { 0 };
+
+ buffer[ 0 ] = 0;
+ buffer[ 1 ] = 1;
+ buffer[ 2 ] = 0; /* Length of the properties is 0. */
+ buffer[ 3 ] = 0x00;
+ buffer[ 4 ] = 0x01;
+ buffer[ 5 ] = 0x02;
+ buffer[ 6 ] = 0x80;
+
+ status = decodeSubackPropertyLength( &buffer[ 2 ], 7, &propertyLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 1, propertyLength );
+
+ buffer[ 2 ] = 2;
+ buffer[ 3 ] = MQTT_PAYLOAD_FORMAT_ID;
+ buffer[ 4 ] = 1;
+
+ status = decodeSubackPropertyLength( &buffer[ 2 ], 7, &propertyLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( 3, propertyLength );
+
+ /* Invalid remaining length. */
+ status = decodeSubackPropertyLength( &buffer[ 2 ], 2, &propertyLength );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ status = decodeSubackPropertyLength( &buffer[ 2 ], 3, &propertyLength );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+void test_MQTT_InitConnect( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+
+ status = MQTT_InitConnect( NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ MQTTConnectionProperties_t connectionProperties;
+ status = MQTT_InitConnect( &connectionProperties );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
+
+/* Comprehensive test for MQTT_ValidateConnectProperties to achieve 100% branch and line coverage */
+
+void test_MQTT_ValidateConnectProperties( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ bool isRequestProblemInfoSet = false;
+ MQTTPropBuilder_t propBuilder;
+ uint8_t buf[ 200 ];
+ uint8_t * pIndex = NULL;
+ uint32_t receiveMaxPropValue = 0;
+
+ /* Test 1: NULL pPropertyBuilder */
+ status = MQTT_ValidateConnectProperties( NULL, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Test 2: NULL pPropertyBuilder->pBuffer */
+ propBuilder.pBuffer = NULL;
+ propBuilder.bufferLength = 200;
+ propBuilder.currentIndex = 0;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Test 3: NULL isRequestProblemInfoSet */
+ propBuilder.pBuffer = buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, NULL, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Test 4: Empty properties (success case) */
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = 200;
+ propBuilder.currentIndex = 0;
+ isRequestProblemInfoSet = true; /* Should be set to false */
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( false, isRequestProblemInfoSet );
+
+ /* Test 4.1: properties with invalid length. */
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = 200;
+ propBuilder.currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ isRequestProblemInfoSet = true; /* Should be set to false */
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Test 5: Valid MQTT_SESSION_EXPIRY_ID */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ propBuilder.currentIndex = 5;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 6: Duplicate MQTT_SESSION_EXPIRY_ID */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 7: Valid MQTT_RECEIVE_MAX_ID with non-zero value */
+ pIndex = buf;
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ propBuilder.currentIndex = 3;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 8: MQTT_RECEIVE_MAX_ID with zero value (error) */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_RECEIVE_MAX_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x00;
+ propBuilder.currentIndex = 3;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 9: Duplicate MQTT_RECEIVE_MAX_ID */
+ pIndex = buf;
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ propBuilder.currentIndex = 6;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 10: Valid MQTT_MAX_PACKET_SIZE_ID with non-zero value */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ propBuilder.currentIndex = 5;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 11: MQTT_MAX_PACKET_SIZE_ID with zero value (error) */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_MAX_PACKET_SIZE_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x00;
+ buf[ 3 ] = 0x00;
+ buf[ 4 ] = 0x00;
+ propBuilder.currentIndex = 5;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 12: Duplicate MQTT_MAX_PACKET_SIZE_ID */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 13: Valid MQTT_TOPIC_ALIAS_MAX_ID */
+ pIndex = buf;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ propBuilder.currentIndex = 3;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 14: Duplicate MQTT_TOPIC_ALIAS_MAX_ID */
+ pIndex = buf;
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ propBuilder.currentIndex = 6;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 15: Valid MQTT_REQUEST_RESPONSE_ID with value 0 */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ 1 ] = 0x00;
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 16: Valid MQTT_REQUEST_RESPONSE_ID with value 1 */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ 1 ] = 0x01;
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 17: MQTT_REQUEST_RESPONSE_ID with invalid value (not 0 or 1) */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ 1 ] = 0x02;
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 18: Duplicate MQTT_REQUEST_RESPONSE_ID */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ 1 ] = 0x01;
+ buf[ 2 ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ 3 ] = 0x00;
+ propBuilder.currentIndex = 4;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 19: Valid MQTT_REQUEST_PROBLEM_ID with value 0 */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ 1 ] = 0x00;
+ propBuilder.currentIndex = 2;
+ isRequestProblemInfoSet = true;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( false, isRequestProblemInfoSet );
+
+ /* Test 20: Valid MQTT_REQUEST_PROBLEM_ID with value 1 */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ 1 ] = 0x01;
+ propBuilder.currentIndex = 2;
+ isRequestProblemInfoSet = false;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( true, isRequestProblemInfoSet );
+
+ /* Test 21: MQTT_REQUEST_PROBLEM_ID with invalid value (not 0 or 1) */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ 1 ] = 0x05;
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 22: Duplicate MQTT_REQUEST_PROBLEM_ID */
+ pIndex = buf;
+ buf[ 0 ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ 1 ] = 0x01;
+ buf[ 2 ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ 3 ] = 0x00;
+ propBuilder.currentIndex = 4;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 23: Valid MQTT_AUTH_METHOD_ID */
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 24: Duplicate MQTT_AUTH_METHOD_ID */
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 25: Valid MQTT_AUTH_DATA_ID */
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status ); /* Should fail - no auth method */
+
+ /* Test 26: Duplicate MQTT_AUTH_DATA_ID */
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 27: Valid MQTT_AUTH_METHOD_ID and MQTT_AUTH_DATA_ID together */
+ pIndex = buf;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 28: Valid MQTT_USER_PROPERTY_ID (can appear multiple times) */
+ pIndex = buf;
+ pIndex = serializeutf_8pair( pIndex );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 29: Multiple MQTT_USER_PROPERTY_ID (should succeed) */
+ pIndex = buf;
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeutf_8pair( pIndex );
+ pIndex = serializeutf_8pair( pIndex );
+ propBuilder.currentIndex = pIndex - buf;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test 30: Invalid property ID (default case) */
+ pIndex = buf;
+ buf[ 0 ] = 0xFF; /* Invalid property ID */
+ buf[ 1 ] = 0x00;
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 31: All valid CONNECT properties together */
+ pIndex = buf;
+ pIndex = serializeuint_32( pIndex, MQTT_SESSION_EXPIRY_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_RECEIVE_MAX_ID );
+ pIndex = serializeuint_32( pIndex, MQTT_MAX_PACKET_SIZE_ID );
+ pIndex = serializeuint_16( pIndex, MQTT_TOPIC_ALIAS_MAX_ID );
+ buf[ pIndex - buf ] = MQTT_REQUEST_RESPONSE_ID;
+ buf[ pIndex - buf + 1 ] = 0x01;
+ pIndex += 2;
+ buf[ pIndex - buf ] = MQTT_REQUEST_PROBLEM_ID;
+ buf[ pIndex - buf + 1 ] = 0x01;
+ pIndex += 2;
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_METHOD_ID );
+ pIndex = serializeutf_8( pIndex, MQTT_AUTH_DATA_ID );
+ pIndex = serializeutf_8pair( pIndex );
+ propBuilder.currentIndex = pIndex - buf;
+ isRequestProblemInfoSet = false;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( true, isRequestProblemInfoSet );
+
+
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, &receiveMaxPropValue );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( true, isRequestProblemInfoSet );
+ TEST_ASSERT_EQUAL( MQTT_TEST_UINT32, receiveMaxPropValue );
+}
+
+/* Additional tests for decode function error paths (insufficient property length) */
+
+void test_MQTT_ValidateConnectProperties_DecodeErrors( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
+ bool isRequestProblemInfoSet = false;
+ MQTTPropBuilder_t propBuilder;
+ uint8_t buf[ 200 ];
+
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = 200;
+
+ /* Test 32: MQTT_SESSION_EXPIRY_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_SESSION_EXPIRY_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x00;
+ /* Missing 2 bytes for uint32 */
+ propBuilder.currentIndex = 3;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 33: MQTT_RECEIVE_MAX_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_RECEIVE_MAX_ID;
+ buf[ 1 ] = 0x00;
+ /* Missing 1 byte for uint16 */
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 34: MQTT_MAX_PACKET_SIZE_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_MAX_PACKET_SIZE_ID;
+ buf[ 1 ] = 0x00;
+ /* Missing 3 bytes for uint32 */
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 35: MQTT_TOPIC_ALIAS_MAX_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_TOPIC_ALIAS_MAX_ID;
+ /* Missing 2 bytes for uint16 */
+ propBuilder.currentIndex = 1;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 36: MQTT_REQUEST_RESPONSE_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ /* Missing 1 byte for uint8 */
+ propBuilder.currentIndex = 1;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 37: MQTT_REQUEST_PROBLEM_ID with insufficient length (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_REQUEST_PROBLEM_ID;
+ /* Missing 1 byte for uint8 */
+ propBuilder.currentIndex = 1;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 38: MQTT_AUTH_METHOD_ID with insufficient length for string length field (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_AUTH_METHOD_ID;
+ buf[ 1 ] = 0x00;
+ /* Missing 1 byte for uint16 length field */
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 39: MQTT_AUTH_METHOD_ID with insufficient length for string data (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_AUTH_METHOD_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x05; /* String length = 5 */
+ buf[ 3 ] = 'a';
+ buf[ 4 ] = 'b';
+ /* Missing 3 bytes of string data */
+ propBuilder.currentIndex = 5;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 40: MQTT_AUTH_DATA_ID with insufficient length for string length field (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_AUTH_DATA_ID;
+ /* Missing 2 bytes for uint16 length field */
+ propBuilder.currentIndex = 1;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 41: MQTT_AUTH_DATA_ID with insufficient length for string data (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_AUTH_DATA_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x10; /* String length = 16 */
+ buf[ 3 ] = 'a';
+ /* Missing 15 bytes of string data */
+ propBuilder.currentIndex = 4;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 42: MQTT_USER_PROPERTY_ID with insufficient length for key length field (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_USER_PROPERTY_ID;
+ buf[ 1 ] = 0x00;
+ /* Missing 1 byte for key length field */
+ propBuilder.currentIndex = 2;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 43: MQTT_USER_PROPERTY_ID with insufficient length for key data (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_USER_PROPERTY_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x05; /* Key length = 5 */
+ buf[ 3 ] = 'k';
+ buf[ 4 ] = 'e';
+ /* Missing 3 bytes of key data */
+ propBuilder.currentIndex = 5;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 44: MQTT_USER_PROPERTY_ID with insufficient length for value length field (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_USER_PROPERTY_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x03; /* Key length = 3 */
+ buf[ 3 ] = 'k';
+ buf[ 4 ] = 'e';
+ buf[ 5 ] = 'y';
+ buf[ 6 ] = 0x00;
+ /* Missing 1 byte for value length field */
+ propBuilder.currentIndex = 7;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+
+ /* Test 45: MQTT_USER_PROPERTY_ID with insufficient length for value data (MQTTBadResponse) */
+ buf[ 0 ] = MQTT_USER_PROPERTY_ID;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x03; /* Key length = 3 */
+ buf[ 3 ] = 'k';
+ buf[ 4 ] = 'e';
+ buf[ 5 ] = 'y';
+ buf[ 6 ] = 0x00;
+ buf[ 7 ] = 0x05; /* Value length = 5 */
+ buf[ 8 ] = 'v';
+ buf[ 9 ] = 'a';
+ /* Missing 3 bytes of value data */
+ propBuilder.currentIndex = 10;
+ status = MQTT_ValidateConnectProperties( &propBuilder, &isRequestProblemInfoSet, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+/* Comprehensive tests for validateReasonCodeForAck (tested via MQTT_SerializeAck) */
+
+void test_validateReasonCodeForAck_PUBACK( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 100 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 100;
+
+ /* Test all valid PUBACK reason codes */
+
+ /* Valid: MQTT_REASON_PUBACK_SUCCESS */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS */
+ reasonCode = MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_UNSPECIFIED_ERROR */
+ reasonCode = MQTT_REASON_PUBACK_UNSPECIFIED_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR */
+ reasonCode = MQTT_REASON_PUBACK_IMPLEMENTATION_SPECIFIC_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_NOT_AUTHORIZED */
+ reasonCode = MQTT_REASON_PUBACK_NOT_AUTHORIZED;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_TOPIC_NAME_INVALID */
+ reasonCode = MQTT_REASON_PUBACK_TOPIC_NAME_INVALID;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE */
+ reasonCode = MQTT_REASON_PUBACK_PACKET_IDENTIFIER_IN_USE;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_QUOTA_EXCEEDED */
+ reasonCode = MQTT_REASON_PUBACK_QUOTA_EXCEEDED;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID */
+ reasonCode = MQTT_REASON_PUBACK_PAYLOAD_FORMAT_INVALID;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid: Use a PUBREC reason code for PUBACK (should fail) */
+ reasonCode = MQTT_REASON_PUBREC_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status ); /* 0x00 is valid for both */
+
+ /* Invalid: Use an invalid reason code for PUBACK */
+ reasonCode = ( MQTTSuccessFailReasonCode_t ) 0xFF;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use a PUBREL-specific reason code for PUBACK */
+ reasonCode = MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_validateReasonCodeForAck_PUBREC( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 100 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 100;
+
+ /* Test all valid PUBREC reason codes */
+
+ /* Valid: MQTT_REASON_PUBREC_SUCCESS */
+ reasonCode = MQTT_REASON_PUBREC_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_NO_MATCHING_SUBSCRIBERS */
+ reasonCode = MQTT_REASON_PUBREC_NO_MATCHING_SUBSCRIBERS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_UNSPECIFIED_ERROR */
+ reasonCode = MQTT_REASON_PUBREC_UNSPECIFIED_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_IMPLEMENTATION_SPECIFIC_ERROR */
+ reasonCode = MQTT_REASON_PUBREC_IMPLEMENTATION_SPECIFIC_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_NOT_AUTHORIZED */
+ reasonCode = MQTT_REASON_PUBREC_NOT_AUTHORIZED;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_TOPIC_NAME_INVALID */
+ reasonCode = MQTT_REASON_PUBREC_TOPIC_NAME_INVALID;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_PACKET_IDENTIFIER_IN_USE */
+ reasonCode = MQTT_REASON_PUBREC_PACKET_IDENTIFIER_IN_USE;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_QUOTA_EXCEEDED */
+ reasonCode = MQTT_REASON_PUBREC_QUOTA_EXCEEDED;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREC_PAYLOAD_FORMAT_INVALID */
+ reasonCode = MQTT_REASON_PUBREC_PAYLOAD_FORMAT_INVALID;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid: Use an invalid reason code for PUBREC */
+ reasonCode = ( MQTTSuccessFailReasonCode_t ) 0xAA;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use a PUBREL-specific reason code for PUBREC */
+ reasonCode = MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_validateReasonCodeForAck_PUBREL( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 100 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 100;
+
+ /* Test all valid PUBREL reason codes */
+
+ /* Valid: MQTT_REASON_PUBREL_SUCCESS */
+ reasonCode = MQTT_REASON_PUBREL_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND */
+ reasonCode = MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid: Use a PUBACK reason code for PUBREL (should fail) */
+ reasonCode = MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use an invalid reason code for PUBREL */
+ reasonCode = ( MQTTSuccessFailReasonCode_t ) 0xBB;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use a PUBREC-specific reason code for PUBREL */
+ reasonCode = MQTT_REASON_PUBREC_UNSPECIFIED_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_validateReasonCodeForAck_PUBCOMP( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 100 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 100;
+
+ /* Test all valid PUBCOMP reason codes */
+
+ /* Valid: MQTT_REASON_PUBCOMP_SUCCESS */
+ reasonCode = MQTT_REASON_PUBCOMP_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Valid: MQTT_REASON_PUBCOMP_PACKET_IDENTIFIER_NOT_FOUND */
+ reasonCode = MQTT_REASON_PUBCOMP_PACKET_IDENTIFIER_NOT_FOUND;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Invalid: Use a PUBACK reason code for PUBCOMP (should fail) */
+ reasonCode = MQTT_REASON_PUBACK_NO_MATCHING_SUBSCRIBERS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use an invalid reason code for PUBCOMP */
+ reasonCode = ( MQTTSuccessFailReasonCode_t ) 0xCC;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid: Use a PUBREC-specific reason code for PUBCOMP */
+ reasonCode = MQTT_REASON_PUBREC_UNSPECIFIED_ERROR;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_validateReasonCodeForAck_InvalidPacketType( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 100 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 100;
+
+ /* Test default case: invalid packet type */
+
+ /* Invalid packet type: MQTT_PACKET_TYPE_CONNECT */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_CONNECT, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid packet type: MQTT_PACKET_TYPE_PUBLISH */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBLISH, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid packet type: MQTT_PACKET_TYPE_SUBSCRIBE */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_SUBSCRIBE, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Invalid packet type: Random value */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, 0xFF, 1, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/* Comprehensive tests for getAckPacketSize (tested via MQTT_SerializeAck) */
+
+void test_getAckPacketSize_NoProperties( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 10 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 10 ];
+
+ /* Setup: Empty properties (currentIndex = 0) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 10;
+ ackProperties.currentIndex = 0;
+ ackProperties.fieldSet = 0;
+
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+
+ /* Test with exact size needed for packet with no properties */
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(0) = 1 byte for property length encoding
+ * - 0 bytes for properties (currentIndex = 0)
+ * - variableLengthEncodedSize(1 + 1 + 0) = variableLengthEncodedSize(2) = 1 byte for remaining length
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 1 + 0 + 1 + 3 = 6 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 6;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 5;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+
+ /* Test with reason code NULL and non-NULL properties. */
+ fixedBuffer.size = 50;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_SmallProperties( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 50 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 50 ];
+
+ /* Setup: Small properties (currentIndex = 10, which is < 128) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 50;
+ ackProperties.currentIndex = 10;
+ ackProperties.fieldSet = 0;
+
+ /* Fill property buffer with dummy data */
+ memset( propBuf, 0xAA, 10 );
+
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(10) = 1 byte for property length encoding
+ * - 10 bytes for properties (currentIndex = 10)
+ * - variableLengthEncodedSize(1 + 1 + 10) = variableLengthEncodedSize(12) = 1 byte for remaining length
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 1 + 10 + 1 + 3 = 16 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 16;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 15;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_MediumProperties_1ByteEncoding( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 200 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 200 ];
+
+ /* Setup: Properties with currentIndex = 100 (< 128, so 1 byte encoding) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 200;
+ ackProperties.currentIndex = 100;
+ ackProperties.fieldSet = 0;
+
+ /* Fill property buffer with dummy data */
+ memset( propBuf, 0xBB, 100 );
+
+ reasonCode = MQTT_REASON_PUBREC_SUCCESS;
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(100) = 1 byte for property length encoding
+ * - 100 bytes for properties (currentIndex = 100)
+ * - variableLengthEncodedSize(1 + 1 + 100) = variableLengthEncodedSize(102) = 1 byte for remaining length
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 1 + 100 + 1 + 3 = 106 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 106;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 105;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_LargeProperties_2ByteEncoding( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 300 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 300 ];
+
+ /* Setup: Properties with currentIndex = 150 (>= 128, < 16384, so 2 byte encoding) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 300;
+ ackProperties.currentIndex = 150;
+ ackProperties.fieldSet = 0;
+
+ /* Fill property buffer with dummy data */
+ memset( propBuf, 0xCC, 150 );
+
+ reasonCode = MQTT_REASON_PUBREL_SUCCESS;
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(150) = 2 bytes for property length encoding (150 >= 128)
+ * - 150 bytes for properties (currentIndex = 150)
+ * - variableLengthEncodedSize(1 + 2 + 150) = variableLengthEncodedSize(153) = 2 bytes for remaining length
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 2 + 150 + 2 + 3 = 158 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 158;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 157;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_BoundaryCase_127Bytes( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 200 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 200 ];
+
+ /* Setup: Properties with currentIndex = 127 (boundary: last value with 1 byte encoding) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 200;
+ ackProperties.currentIndex = 127;
+ ackProperties.fieldSet = 0;
+
+ /* Fill property buffer with dummy data */
+ memset( propBuf, 0xDD, 127 );
+
+ reasonCode = MQTT_REASON_PUBCOMP_SUCCESS;
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(127) = 1 byte for property length encoding (127 < 128)
+ * - 127 bytes for properties (currentIndex = 127)
+ * - variableLengthEncodedSize(1 + 1 + 127) = variableLengthEncodedSize(129) = 2 bytes for remaining length (129 >= 128)
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 1 + 127 + 2 + 3 = 134 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 134;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 133;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_BoundaryCase_128Bytes( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 200 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 200 ];
+
+ /* Setup: Properties with currentIndex = 128 (boundary: first value with 2 byte encoding) */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 200;
+ ackProperties.currentIndex = 128;
+ ackProperties.fieldSet = 0;
+
+ /* Fill property buffer with dummy data */
+ memset( propBuf, 0xEE, 128 );
+
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+
+ /* Expected size calculation:
+ * - 1 byte for reason code
+ * - variableLengthEncodedSize(128) = 2 bytes for property length encoding (128 >= 128)
+ * - 128 bytes for properties (currentIndex = 128)
+ * - variableLengthEncodedSize(1 + 2 + 128) = variableLengthEncodedSize(131) = 2 bytes for remaining length
+ * - 3 bytes for header (1) + packet ID (2)
+ * Total: 1 + 2 + 128 + 2 + 3 = 136 bytes
+ */
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 136;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test with buffer too small (should fail) */
+ fixedBuffer.size = 135;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+void test_getAckPacketSize_AllPacketTypes( void )
+{
+ MQTTStatus_t status;
+ MQTTFixedBuffer_t fixedBuffer;
+ uint8_t buf[ 50 ];
+ MQTTSuccessFailReasonCode_t reasonCode;
+ MQTTPropBuilder_t ackProperties;
+ uint8_t propBuf[ 50 ];
+
+ /* Setup: Small properties */
+ ackProperties.pBuffer = propBuf;
+ ackProperties.bufferLength = 50;
+ ackProperties.currentIndex = 5;
+ ackProperties.fieldSet = 0;
+ memset( propBuf, 0xFF, 5 );
+
+ fixedBuffer.pBuffer = buf;
+ fixedBuffer.size = 50;
+
+ /* Test PUBACK */
+ reasonCode = MQTT_REASON_PUBACK_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBACK, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test PUBREC */
+ reasonCode = MQTT_REASON_PUBREC_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREC, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test PUBREL */
+ reasonCode = MQTT_REASON_PUBREL_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBREL, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ /* Test PUBCOMP */
+ reasonCode = MQTT_REASON_PUBCOMP_SUCCESS;
+ status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_PUBCOMP, 1, &ackProperties, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+}
+
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* MQTT_SkipNextProperty Tests */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* NULL Parameter Tests */
+/* ========================================================================== */
+
+/**
+ * @brief Test MQTT_SkipNextProperty with NULL pPropertyBuilder parameter.
+ */
+void test_MQTT_SkipNextProperty_NullPropertyBuilder( void )
+{
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ status = MQTT_SkipNextProperty( NULL, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Test MQTT_SkipNextProperty with NULL currentIndex parameter.
+ */
+void test_MQTT_SkipNextProperty_NullCurrentIndex( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ status = MQTT_SkipNextProperty( &propBuilder, NULL );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Test MQTT_SkipNextProperty with NULL pBuffer in property builder.
+ */
+void test_MQTT_SkipNextProperty_NullBuffer( void )
+{
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = NULL;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/* ========================================================================== */
+/* Index Boundary Tests */
+/* ========================================================================== */
+
+/**
+ * @brief Test MQTT_SkipNextProperty with currentIndex at end of properties.
+ */
+void test_MQTT_SkipNextProperty_IndexAtEnd( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+ propBuilder.currentIndex = 0;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTEndOfProperties, status );
+}
+
+/**
+ * @brief Test MQTT_SkipNextProperty with currentIndex beyond end.
+ */
+void test_MQTT_SkipNextProperty_IndexBeyondEnd( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 10;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+ propBuilder.currentIndex = 5;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTEndOfProperties, status );
+}
+
+/* ========================================================================== */
+/* Unknown Property ID Tests */
+/* ========================================================================== */
+
+/**
+ * @brief Test MQTT_SkipNextProperty with unknown property ID.
+ */
+void test_MQTT_SkipNextProperty_UnknownPropertyId( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ /* Set an invalid property ID */
+ testBuffer[ 0 ] = 0xFF;
+ propBuilder.currentIndex = 10;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+
+/* ========================================================================== */
+/* Four-Byte Integer Property Tests */
+/* ========================================================================== */
+
+/**
+ * @brief Test skipping SESSION_EXPIRY property (4-byte integer).
+ */
+void test_MQTT_SkipNextProperty_SessionExpiry( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ /* Encode SESSION_EXPIRY property */
+ *pIndex++ = MQTT_SESSION_EXPIRY_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
+}
+
+/**
+ * @brief Test skipping MAX_PACKET_SIZE property (4-byte integer).
+ */
+void test_MQTT_SkipNextProperty_MaxPacketSize( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_MAX_PACKET_SIZE_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
+}
+
+/**
+ * @brief Test skipping WILL_DELAY property (4-byte integer).
+ */
+void test_MQTT_SkipNextProperty_WillDelay( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_WILL_DELAY_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
+}
+
+/**
+ * @brief Test skipping MSG_EXPIRY property (4-byte integer).
+ */
+void test_MQTT_SkipNextProperty_MessageExpiry( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_MSG_EXPIRY_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
+}
+
+/**
+ * @brief Test skipping 4-byte integer property with insufficient buffer.
+ */
+void test_MQTT_SkipNextProperty_Uint32_InsufficientBuffer( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ testBuffer[ 0 ] = MQTT_SESSION_EXPIRY_ID;
+ /* Only 3 bytes available instead of 4 */
+ propBuilder.currentIndex = 4;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+/* ========================================================================== */
+/* Two-Byte Integer Property Tests */
+/* ========================================================================== */
+
+/**
+ * @brief Test skipping RECEIVE_MAX property (2-byte integer).
+ */
+void test_MQTT_SkipNextProperty_ReceiveMax( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_RECEIVE_MAX_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
+}
+
+/**
+ * @brief Test skipping TOPIC_ALIAS_MAX property (2-byte integer).
+ */
+void test_MQTT_SkipNextProperty_TopicAliasMax( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
- MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- publishInfo.qos = MQTTQoS1;
+ *pIndex++ = MQTT_TOPIC_ALIAS_MAX_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set except QoS1 and publish flag. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 1 ) | 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
}
-/* ========================================================================== */
+/**
+ * @brief Test skipping TOPIC_ALIAS property (2-byte integer).
+ */
+void test_MQTT_SkipNextProperty_TopicAlias( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_TOPIC_ALIAS_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
+}
/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ * @brief Test skipping SERVER_KEEP_ALIVE property (2-byte integer).
*/
-void test_MQTT_SerializePublishHeaderWithoutTopic_QoS2( void )
+void test_MQTT_SkipNextProperty_ServerKeepAlive( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
- MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- publishInfo.qos = MQTTQoS2;
+ *pIndex++ = MQTT_SERVER_KEEP_ALIVE_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set except QoS2. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 2 ) | 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
+}
+
+/**
+ * @brief Test skipping 2-byte integer property with insufficient buffer.
+ */
+void test_MQTT_SkipNextProperty_Uint16_InsufficientBuffer( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ testBuffer[ 0 ] = MQTT_RECEIVE_MAX_ID;
+ /* Only 1 byte available instead of 2 */
+ propBuilder.currentIndex = 2;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
+/* ========================================================================== */
+/* One-Byte Integer Property Tests */
/* ========================================================================== */
/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ * @brief Test skipping REQUEST_RESPONSE property (1-byte integer).
*/
-void test_MQTT_SerializePublishHeaderWithoutTopic_retain( void )
+void test_MQTT_SkipNextProperty_RequestResponse( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
- MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- publishInfo.retain = true;
+ *pIndex++ = MQTT_REQUEST_RESPONSE_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set except retain flag. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 0 ) | 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping REQUEST_PROBLEM property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_RequestProblem( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_REQUEST_PROBLEM_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping PAYLOAD_FORMAT property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_PayloadFormat( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_PAYLOAD_FORMAT_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping MAX_QOS property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_MaxQos( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_MAX_QOS_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping RETAIN_AVAILABLE property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_RetainAvailable( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_RETAIN_AVAILABLE_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping WILDCARD property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_Wildcard( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_WILDCARD_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping SUB_AVAILABLE property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_SubAvailable( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_SUB_AVAILABLE_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping SHARED_SUB property (1-byte integer).
+ */
+void test_MQTT_SkipNextProperty_SharedSub( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_SHARED_SUB_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
+
+/**
+ * @brief Test skipping 1-byte integer property with insufficient buffer.
+ */
+void test_MQTT_SkipNextProperty_Uint8_InsufficientBuffer( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ testBuffer[ 0 ] = MQTT_REQUEST_RESPONSE_ID;
+ /* No bytes available for the value */
+ propBuilder.currentIndex = 1;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
+/* ========================================================================== */
+/* UTF-8 String Property Tests */
/* ========================================================================== */
/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ * @brief Test skipping AUTH_METHOD property (UTF-8 string).
*/
-void test_MQTT_SerializePublishHeaderWithoutTopic_Duplicate( void )
+void test_MQTT_SkipNextProperty_AuthMethod( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
- MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_AUTH_METHOD_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
+
+/**
+ * @brief Test skipping CONTENT_TYPE property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_ContentType( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_CONTENT_TYPE_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
+
+/**
+ * @brief Test skipping RESPONSE_TOPIC property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_ResponseTopic( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_RESPONSE_TOPIC_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
+
+/**
+ * @brief Test skipping ASSIGNED_CLIENT_ID property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_AssignedClientId( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_ASSIGNED_CLIENT_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
+
+/**
+ * @brief Test skipping REASON_STRING property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_ReasonString( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+
+ *pIndex++ = MQTT_REASON_STRING_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
+
+/**
+ * @brief Test skipping RESPONSE_INFO property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_ResponseInfo( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- publishInfo.dup = true;
+ *pIndex++ = MQTT_RESPONSE_INFO_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set except dup. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 3 ) | 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 0U );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
}
-/* ========================================================================== */
-
/**
- * @brief Tests that MQTT_SerializePublishHeaderWithoutTopic works as intended.
+ * @brief Test skipping SERVER_REF property (UTF-8 string).
*/
-void test_MQTT_SerializePublishHeaderWithoutTopic_VariousFlagsSetTopicLength( void )
+void test_MQTT_SkipNextProperty_ServerRef( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 7 ];
- MQTTStatus_t status = MQTTSuccess;
- size_t headerSize = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- publishInfo.qos = MQTTQoS2;
- publishInfo.dup = true;
- publishInfo.retain = true;
- publishInfo.topicNameLength = 20;
+ *pIndex++ = MQTT_SERVER_REF_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
- status = MQTT_SerializePublishHeaderWithoutTopic( &publishInfo,
- remainingLength,
- buffer,
- &headerSize );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( headerSize, 4U );
- /* No flag should be set except QoS2/dup/retain. */
- TEST_ASSERT_EQUAL( buffer[ 0 ], ( 1U << 2 ) | ( 1U << 3 ) | ( 1U << 0 ) | 0x30 );
- /* The encoded length must be 0. */
- TEST_ASSERT_EQUAL( buffer[ 1 ], 0U );
- /* The topic name length should be 0 too. */
- TEST_ASSERT_EQUAL( buffer[ 2 ], 0U );
- TEST_ASSERT_EQUAL( buffer[ 3 ], 20U );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
}
-/* ========================================================================== */
-
/**
- * @brief Tests that MQTT_SerializePublishHeader works as intended.
+ * @brief Test skipping AUTH_DATA property (UTF-8 string).
*/
-void test_MQTT_SerializePublishHeader( void )
+void test_MQTT_SkipNextProperty_AuthData( void )
{
- MQTTPublishInfo_t publishInfo;
- size_t remainingLength = 0;
- uint8_t buffer[ 200 + 2 * BUFFER_PADDING_LENGTH ];
- uint8_t expectedPacket[ 200 ];
- uint8_t * pIterator;
- size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- size_t packetSize = bufferSize;
- MQTTStatus_t status = MQTTSuccess;
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
- size_t headerSize = 0;
-
- const uint16_t PACKET_ID = 1;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify bad parameters fail. */
- memset( &publishInfo, 0x00, sizeof( publishInfo ) );
- publishInfo.pTopicName = TEST_TOPIC_NAME;
- publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
- status = MQTT_SerializePublishHeader( NULL,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- NULL,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ *pIndex++ = MQTT_AUTH_DATA_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- /* Verify a NULL buffer in the fixed buffer struct fails */
- fixedBuffer.pBuffer = NULL;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Restore the fixed buffer. */
- fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- /* Empty topic fails. */
- publishInfo.pTopicName = NULL;
- publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
- publishInfo.pTopicName = TEST_TOPIC_NAME;
- publishInfo.topicNameLength = 0;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- publishInfo.topicNameLength = TEST_TOPIC_NAME_LENGTH;
+/**
+ * @brief Test skipping CORRELATION_DATA property (UTF-8 string).
+ */
+void test_MQTT_SkipNextProperty_CorrelationData( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* 0 packet ID for QoS > 0. */
- publishInfo.qos = MQTTQoS1;
- status = MQTT_SerializePublishHeader( &publishInfo,
- 0,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Verify that a duplicate flag for Qos 0 fails. */
- publishInfo.qos = MQTTQoS0;
- publishInfo.dup = true;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ *pIndex++ = MQTT_CORRELATION_DATA_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
- /* Restore the previous flags for other tests. */
- publishInfo.qos = MQTTQoS1;
- publishInfo.dup = false;
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- /* Buffer too small. */
- fixedBuffer.size = 1;
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
- fixedBuffer.size = bufferSize;
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- /* Success case. */
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 + MQTT_TEST_UTF8_STRING_LENGTH, currentIndex );
+}
- /* MQTT PUBLISH packet format:
- * 0x30 | publish flags (dup, qos, retain) (1 byte)
- * Remaining length (1-4 bytes)
- * Topic name length (2 bytes)
- * Topic name (variable)
- * Packet ID (if QoS > 0) (1 byte)
- * Payload (>= 0 bytes) */
- memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
- pIterator = expectedPacket;
- *pIterator++ = MQTT_PACKET_TYPE_PUBLISH | ( publishInfo.qos << 1 );
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- pIterator += encodeString( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
- *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
- *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+/**
+ * @brief Test skipping UTF-8 string property with insufficient buffer for length.
+ */
+void test_MQTT_SkipNextProperty_Utf8_InsufficientBufferForLength( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
- publishInfo.qos = MQTTQoS0;
- publishInfo.pPayload = "test";
- publishInfo.payloadLength = 4;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializePublishHeader( &publishInfo,
- 0,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
- pIterator = expectedPacket;
- *pIterator++ = MQTT_PACKET_TYPE_PUBLISH;
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- pIterator += encodeString( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
- /* Payload should not be serialized. */
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
+ testBuffer[ 0 ] = MQTT_AUTH_METHOD_ID;
+ /* Only 1 byte available for length (need 2) */
+ propBuilder.currentIndex = 2;
- /* Again with QoS2 and dup. */
- publishInfo.qos = MQTTQoS2;
- publishInfo.dup = true;
- status = MQTT_GetPublishPacketSize( &publishInfo, &remainingLength, &packetSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializePublishHeader( &publishInfo,
- PACKET_ID,
- remainingLength,
- &fixedBuffer,
- &headerSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- memset( expectedPacket, 0x00, sizeof( expectedPacket ) );
- pIterator = expectedPacket;
- /* Set the flags as follows: Dup = 0x8, QoS2 = 0x4, 8 | 4 = 0xC. */
- *pIterator++ = MQTT_PACKET_TYPE_PUBLISH | 0xC;
- pIterator += encodeRemainingLength( pIterator, remainingLength );
- pIterator += encodeString( pIterator, publishInfo.pTopicName, publishInfo.topicNameLength );
- *pIterator++ = UINT16_HIGH_BYTE( PACKET_ID );
- *pIterator++ = UINT16_LOW_BYTE( PACKET_ID );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], packetSize );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
-/* ========================================================================== */
-
-void test_MQTT_ProcessIncomingPacketTypeAndLength_PacketNULL( void )
+/**
+ * @brief Test skipping UTF-8 string property with insufficient buffer for data.
+ */
+void test_MQTT_SkipNextProperty_Utf8_InsufficientBufferForData( void )
{
- uint8_t pBuffer[ 100 ] = { 0 };
- size_t index = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, NULL );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+ *pIndex++ = MQTT_AUTH_METHOD_ID;
+ *pIndex++ = 0x00;
+ *pIndex++ = 0x10; /* Length = 16 */
+
+ /* Only 5 bytes available for data (need 16) */
+ propBuilder.currentIndex = 8;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
+/* ========================================================================== */
+/* User Property Tests */
/* ========================================================================== */
-void test_MQTT_ProcessIncomingPacketTypeAndLength_BufferNULL( void )
+/**
+ * @brief Test skipping USER_PROPERTY (two UTF-8 strings).
+ */
+void test_MQTT_SkipNextProperty_UserProperty( void )
{
- MQTTPacketInfo_t packetInfo;
- size_t index = 0;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- status = MQTT_ProcessIncomingPacketTypeAndLength( NULL, &index, &packetInfo );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-}
+ *pIndex++ = MQTT_USER_PROPERTY_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
-/* ========================================================================== */
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
-void test_MQTT_ProcessIncomingPacketTypeAndLength_IndexNULL( void )
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 1 + 2 * ( 2 + MQTT_TEST_UTF8_STRING_LENGTH ), currentIndex );
+}
+
+/**
+ * @brief Test skipping USER_PROPERTY with insufficient buffer for key.
+ */
+void test_MQTT_SkipNextProperty_UserProperty_InsufficientBufferForKey( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ] = { 0 };
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, NULL, &packetInfo );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- TEST_ASSERT_EQUAL( MQTTBadParameter, status );
-}
+ testBuffer[ 0 ] = MQTT_USER_PROPERTY_ID;
+ testBuffer[ 1 ] = 0x00;
+ testBuffer[ 2 ] = 0x10; /* Key length = 16 */
-/* ========================================================================== */
+ /* Only 5 bytes available (need 16 for key + 2 for value length) */
+ propBuilder.currentIndex = 8;
-void test_MQTT_ProcessIncomingPacketTypeAndLength_NoData( void )
-{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ] = { 0 };
- size_t index = 0;
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
+}
+
+/**
+ * @brief Test skipping USER_PROPERTY with insufficient buffer for value.
+ */
+void test_MQTT_SkipNextProperty_UserProperty_InsufficientBufferForValue( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- TEST_ASSERT_EQUAL( MQTTNoDataAvailable, status );
+ *pIndex++ = MQTT_USER_PROPERTY_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ *pIndex++ = 0x00;
+ *pIndex++ = 0x10; /* Value length = 16 */
+
+ /* Not enough bytes for value data */
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer ) + 5;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
+/* ========================================================================== */
+/* Variable Byte Integer Property Tests */
/* ========================================================================== */
-void test_MQTT_ProcessIncomingPacketTypeAndLength_InvalidData( void )
+/**
+ * @brief Test skipping SUBSCRIPTION_ID property (variable byte integer, 1 byte).
+ */
+void test_MQTT_SkipNextProperty_SubscriptionId_OneByte( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ];
- size_t index = 2;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
- memset( pBuffer, 0, 100 );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- pBuffer[ 0 ] = 0xF0;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ *pIndex++ = 0x7F; /* 127 - single byte encoding */
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- TEST_ASSERT_EQUAL( MQTTBadResponse, status );
-}
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
-/* ========================================================================== */
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
+}
-void test_MQTT_ProcessIncomingPacketTypeAndLength_ValidDataOneByte( void )
+/**
+ * @brief Test skipping SUBSCRIPTION_ID property (variable byte integer, 2 bytes).
+ */
+void test_MQTT_SkipNextProperty_SubscriptionId_TwoBytes( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ];
- size_t index = 1;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
- memset( pBuffer, 0, 100 );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ *pIndex++ = 0x80; /* Continuation bit set */
+ *pIndex++ = 0x01; /* 128 - two byte encoding */
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- TEST_ASSERT_EQUAL( MQTTNeedMoreBytes, status );
-}
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
-/* ========================================================================== */
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
+}
-void test_MQTT_ProcessIncomingPacketTypeAndLength_ValidDataTwoBytes( void )
+/**
+ * @brief Test skipping SUBSCRIPTION_ID property (variable byte integer, 4 bytes).
+ */
+void test_MQTT_SkipNextProperty_SubscriptionId_FourBytes( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ];
- size_t index = 2;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
- memset( pBuffer, 0, 100 );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
- /* 2nd byte is the length. */
- pBuffer[ 1 ] = 10;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ pIndex += encodeVariableLengthUT( pIndex, 268435455 ); /* Max value, 4 bytes */
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
- TEST_ASSERT_EQUAL( packetInfo.remainingLength, 10U );
- TEST_ASSERT_EQUAL( packetInfo.headerLength, 2U );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
}
-/* ========================================================================== */
-
-void test_MQTT_ProcessIncomingPacketTypeAndLength_InvalidLength( void )
+/**
+ * @brief Test skipping SUBSCRIPTION_ID with insufficient buffer.
+ */
+void test_MQTT_SkipNextProperty_SubscriptionId_InsufficientBuffer( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ];
- size_t index = 6;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
- memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
- memset( pBuffer, 0, 100 );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
- /* 2nd byte onward is the length. */
- pBuffer[ 1 ] = 0xFF;
- pBuffer[ 2 ] = 0xFF;
- pBuffer[ 3 ] = 0xFF;
- /* This byte doesn't terminate the length. */
- pBuffer[ 4 ] = 0xFF;
- pBuffer[ 5 ] = 0xFF;
+ testBuffer[ 0 ] = MQTT_SUBSCRIPTION_ID_ID;
+ testBuffer[ 1 ] = 0x80; /* Continuation bit set, but no next byte */
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.currentIndex = 2;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
-/* ========================================================================== */
-
-void test_MQTT_ProcessIncomingPacketTypeAndLength_NonConformingLength( void )
+/**
+ * @brief Test skipping SUBSCRIPTION_ID with invalid encoding (5 bytes).
+ */
+void test_MQTT_SkipNextProperty_SubscriptionId_InvalidEncoding( void )
{
- MQTTPacketInfo_t packetInfo;
- uint8_t pBuffer[ 100 ];
- size_t index = 6;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- memset( &packetInfo, 0, sizeof( MQTTPacketInfo_t ) );
- memset( pBuffer, 0, 100 );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
- /* 2nd byte onward is the length. */
- pBuffer[ 1 ] = 0x80;
- pBuffer[ 2 ] = 0x80;
- pBuffer[ 3 ] = 0x80;
- /* This byte doesn't terminate the length. */
- pBuffer[ 4 ] = 0x00;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ *pIndex++ = 0xFF; /* All continuation bits set */
+ *pIndex++ = 0xFF;
+ *pIndex++ = 0xFF;
+ *pIndex++ = 0xFF;
+ *pIndex++ = 0x7F; /* 5 bytes - invalid */
- status = MQTT_ProcessIncomingPacketTypeAndLength( pBuffer, &index, &packetInfo );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
+/* ========================================================================== */
+/* Multiple Properties Tests */
/* ========================================================================== */
/**
- * @brief Tests that MQTT_SerializeAck works as intended.
+ * @brief Test skipping multiple properties in sequence.
*/
-void test_MQTT_SerializeAck( void )
+void test_MQTT_SkipNextProperty_MultipleProperties( void )
{
- uint8_t buffer[ 10 + 2 * BUFFER_PADDING_LENGTH ];
- uint8_t expectedPacket[ MQTT_PUBLISH_ACK_PACKET_SIZE ];
- size_t bufferSize = sizeof( buffer ) - 2 * BUFFER_PADDING_LENGTH;
- MQTTStatus_t status = MQTTSuccess;
- MQTTFixedBuffer_t fixedBuffer = { .pBuffer = &buffer[ BUFFER_PADDING_LENGTH ], .size = bufferSize };
- uint8_t packetType = MQTT_PACKET_TYPE_PUBACK;
-
- const uint16_t PACKET_ID = 1;
-
- expectedPacket[ 0 ] = packetType;
- expectedPacket[ 1 ] = 2U;
- expectedPacket[ 2 ] = UINT16_HIGH_BYTE( PACKET_ID );
- expectedPacket[ 3 ] = UINT16_LOW_BYTE( PACKET_ID );
-
- /* Verify invalid parameter failures. */
- status = MQTT_SerializeAck( NULL, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- status = MQTT_SerializeAck( &fixedBuffer, packetType, 0 );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Verify a NULL buffer in the fixed buffer struct fails */
- fixedBuffer.pBuffer = NULL;
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Add SESSION_EXPIRY (4 bytes) */
+ *pIndex++ = MQTT_SESSION_EXPIRY_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
- /* Restore the fixed buffer. */
- fixedBuffer.pBuffer = &buffer[ BUFFER_PADDING_LENGTH ];
+ /* Add RECEIVE_MAX (2 bytes) */
+ *pIndex++ = MQTT_RECEIVE_MAX_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
- /* Not a PUBACK, PUBREC, PUBREL, or PUBCOMP. */
- status = MQTT_SerializeAck( &fixedBuffer, MQTT_PACKET_TYPE_CONNACK, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ /* Add MAX_QOS (1 byte) */
+ *pIndex++ = MQTT_MAX_QOS_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
- /* An ack is 4 bytes. */
- fixedBuffer.size = 3;
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
- fixedBuffer.size = bufferSize;
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- /* Good case succeeds. */
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], MQTT_PUBLISH_ACK_PACKET_SIZE );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ /* Skip first property */
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
- /* QoS 2 acks. */
- packetType = MQTT_PACKET_TYPE_PUBREC;
- expectedPacket[ 0 ] = packetType;
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], MQTT_PUBLISH_ACK_PACKET_SIZE );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ /* Skip second property */
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 8, currentIndex );
- packetType = MQTT_PACKET_TYPE_PUBREL;
- expectedPacket[ 0 ] = packetType;
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], MQTT_PUBLISH_ACK_PACKET_SIZE );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ /* Skip third property */
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 10, currentIndex );
- packetType = MQTT_PACKET_TYPE_PUBCOMP;
- expectedPacket[ 0 ] = packetType;
- padAndResetBuffer( buffer, sizeof( buffer ) );
- status = MQTT_SerializeAck( &fixedBuffer, packetType, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_MEMORY( expectedPacket, &buffer[ BUFFER_PADDING_LENGTH ], MQTT_PUBLISH_ACK_PACKET_SIZE );
- checkBufferOverflow( buffer, sizeof( buffer ) );
+ /* Try to skip beyond end */
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+ TEST_ASSERT_EQUAL( MQTTEndOfProperties, status );
}
-/* ===================== Testing MQTT_SerializeConnect ===================== */
-
/**
- * @brief Check the serialization of an MQTT CONNECT packet in the given buffer,
- * following the same order in serializeConnectPacket.
- *
- * @param[in] pConnectInfo MQTT CONNECT packet parameters.
- * @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
- * @param[in] remainingLength Remaining Length of MQTT CONNECT packet.
- * @param[in] pBuffer Buffer to check packet serialization.
- *
+ * @brief Test skipping property at exact buffer boundary.
*/
-static void verifySerializedConnectPacket( const MQTTConnectInfo_t * const pConnectInfo,
- const MQTTPublishInfo_t * const pWillInfo,
- size_t remainingLength,
- const MQTTFixedBuffer_t * const pBuffer )
+void test_MQTT_SkipNextProperty_AtBufferBoundary( void )
{
- uint8_t connectFlags = 0U;
- uint8_t encodedRemainingLength = 0U;
- uint8_t encodedStringLength = 0U;
- uint8_t * pIndex = NULL;
-
- pIndex = pBuffer->pBuffer;
- /* The first byte in the CONNECT packet is the control packet type. */
- TEST_ASSERT_EQUAL_MESSAGE( MQTT_PACKET_TYPE_CONNECT, *pIndex, "MQTT_PACKET_TYPE_CONNECT is not equal to *pIndex" );
- pIndex++;
-
- /* The remaining length of the CONNECT packet is encoded starting from the
- * second byte. The remaining length does not include the length of the fixed
- * header or the encoding of the remaining length. */
- encodedRemainingLength = encodeRemainingLength( remainingLengthBuffer, remainingLength );
- TEST_ASSERT_EQUAL_MEMORY( remainingLengthBuffer, pIndex, encodedRemainingLength );
- pIndex += encodedRemainingLength;
-
- /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable
- * header. This string is 4 bytes long. */
- encodedStringLength = encodeString( encodedStringBuffer, "MQTT", 4 );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
-
- /* The MQTT protocol version is the second field of the variable header. */
- TEST_ASSERT_EQUAL( MQTT_VERSION_3_1_1, *pIndex );
- pIndex++;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Set the clean session flag if needed. */
- if( pConnectInfo->cleanSession == true )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
- }
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Set the flags for username and password if provided. */
- if( pConnectInfo->pUserName != NULL )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
- }
+ *pIndex++ = MQTT_MAX_QOS_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
- if( pConnectInfo->pPassword != NULL )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
- }
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- /* Set will flag if a Last Will and Testament is provided. */
- if( pWillInfo != NULL )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- /* Flags only need to be changed for Will QoS 1 or 2. */
- if( pWillInfo->qos == MQTTQoS1 )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
- }
- else if( pWillInfo->qos == MQTTQoS2 )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
- }
- else
- {
- /* Empty else MISRA 15.7 */
- }
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( propBuilder.currentIndex, currentIndex );
+}
- if( pWillInfo->retain == true )
- {
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
- }
- }
+/* ========================================================================== */
+/* Edge Case Tests */
+/* ========================================================================== */
- TEST_ASSERT_EQUAL( connectFlags, *pIndex );
- pIndex++;
+/**
+ * @brief Test skipping property with zero-length UTF-8 string.
+ */
+void test_MQTT_SkipNextProperty_ZeroLengthString( void )
+{
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Verify the 2 bytes of the keep alive interval into the CONNECT packet. */
- TEST_ASSERT_EQUAL( UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds ),
- *pIndex );
- pIndex++;
- TEST_ASSERT_EQUAL( UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds ),
- *pIndex );
- pIndex++;
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Verify the client identifier into the CONNECT packet. */
- encodedStringLength = encodeString( encodedStringBuffer,
- pConnectInfo->pClientIdentifier,
- pConnectInfo->clientIdentifierLength );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
+ *pIndex++ = MQTT_AUTH_METHOD_ID;
+ *pIndex++ = 0x00;
+ *pIndex++ = 0x00; /* Length = 0 */
- /* Verify the will topic name and message into the CONNECT packet if provided. */
- if( pWillInfo != NULL )
- {
- encodedStringLength = encodeString( encodedStringBuffer,
- pWillInfo->pTopicName,
- pWillInfo->topicNameLength );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
- encodedStringLength = encodeString( encodedStringBuffer,
- pWillInfo->pPayload,
- ( uint16_t ) pWillInfo->payloadLength );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
- }
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
- /* Verify the user name if provided. */
- if( pConnectInfo->pUserName != NULL )
- {
- encodedStringLength = encodeString( encodedStringBuffer,
- pConnectInfo->pUserName,
- pConnectInfo->userNameLength );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
- }
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- /* Verify the password if provided. */
- if( pConnectInfo->pPassword != NULL )
- {
- encodedStringLength = encodeString( encodedStringBuffer,
- pConnectInfo->pPassword,
- pConnectInfo->passwordLength );
- TEST_ASSERT_EQUAL_MEMORY( encodedStringBuffer, pIndex, encodedStringLength );
- pIndex += encodedStringLength;
- }
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 3, currentIndex );
}
/**
- * @brief Call Mqtt_SerializeConnect using NULL parameters and insufficient buffer
- * size until we receive all possible MQTTBadParameter and MQTTNoMemory errors.
+ * @brief Test skipping USER_PROPERTY with zero-length key and value.
*/
-void test_MQTT_SerializeConnect_Invalid_Params()
+void test_MQTT_SkipNextProperty_UserProperty_ZeroLength( void )
{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- size_t remainingLength = 0UL, packetSize = 0UL;
- MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTConnectInfo_t connectInfo;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Test NULL pConnectInfo. */
- mqttStatus = MQTT_SerializeConnect( NULL, NULL,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Test NULL pBuffer. */
- mqttStatus = MQTT_SerializeConnect( &connectInfo, NULL,
- remainingLength, NULL );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ *pIndex++ = MQTT_USER_PROPERTY_ID;
+ *pIndex++ = 0x00;
+ *pIndex++ = 0x00; /* Key length = 0 */
+ *pIndex++ = 0x00;
+ *pIndex++ = 0x00; /* Value length = 0 */
- /* Test connectPacketSize > pBuffer->size. */
- /* Get MQTT connect packet size and remaining length. */
- setupConnectInfo( &connectInfo );
- mqttStatus = MQTT_GetConnectPacketSize( &connectInfo,
- NULL,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- networkBuffer.pBuffer = mqttBuffer;
- networkBuffer.size = packetSize - 1;
- mqttStatus = MQTT_SerializeConnect( &connectInfo, NULL,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTNoMemory, mqttStatus );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 5, currentIndex );
}
/**
- * @brief This method calls MQTT_SerializeConnect successfully using different parameters
- * until we have full coverage on the private method, serializeConnectPacket(...).
+ * @brief Test skipping SUBSCRIPTION_ID with value 0 (invalid but should skip).
*/
-void test_MQTT_SerializeConnect_Happy_Paths()
+void test_MQTT_SkipNextProperty_SubscriptionId_Zero( void )
{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- size_t remainingLength = 0;
- size_t packetSize = 0;
- MQTTFixedBuffer_t networkBuffer;
- MQTTConnectInfo_t connectInfo;
- MQTTPublishInfo_t willInfo;
-
- /* Fill structs to pass into methods to be tested. */
- setupNetworkBuffer( &networkBuffer );
- setupConnectInfo( &connectInfo );
- setupPublishInfo( &willInfo );
- willInfo.dup = true;
- willInfo.retain = true;
-
- /* Get MQTT connect packet size and remaining length. */
- mqttStatus = MQTT_GetConnectPacketSize( &connectInfo,
- &willInfo,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Make sure buffer has enough space. */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, networkBuffer.size );
- mqttStatus = MQTT_SerializeConnect( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- verifySerializedConnectPacket( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
-
- /* Repeat with MQTTQoS1. */
- willInfo.qos = MQTTQoS1;
- mqttStatus = MQTT_GetConnectPacketSize( &connectInfo,
- &willInfo,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Make sure buffer has enough space. */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, networkBuffer.size );
- mqttStatus = MQTT_SerializeConnect( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- verifySerializedConnectPacket( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Re-initialize objects for branch coverage. */
- willInfo.pPayload = MQTT_SAMPLE_PAYLOAD;
- willInfo.payloadLength = MQTT_SAMPLE_PAYLOAD_LEN;
- willInfo.pTopicName = MQTT_CLIENT_IDENTIFIER;
- willInfo.topicNameLength = MQTT_CLIENT_IDENTIFIER_LEN;
- willInfo.dup = true;
- willInfo.qos = MQTTQoS2;
- willInfo.retain = false;
- connectInfo.cleanSession = false;
- connectInfo.pClientIdentifier = MQTT_CLIENT_IDENTIFIER;
- connectInfo.clientIdentifierLength = MQTT_CLIENT_IDENTIFIER_LEN;
- connectInfo.pUserName = NULL;
- connectInfo.userNameLength = 0;
- connectInfo.pPassword = NULL;
- connectInfo.passwordLength = 0;
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ *pIndex++ = 0x00; /* Value = 0 */
- mqttStatus = MQTT_GetConnectPacketSize( &connectInfo,
- NULL,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Make sure buffer has enough space. */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, networkBuffer.size );
- mqttStatus = MQTT_SerializeConnect( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- verifySerializedConnectPacket( &connectInfo, &willInfo,
- remainingLength, &networkBuffer );
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
- /* Repeat with NULL pWillInfo. */
- mqttStatus = MQTT_GetConnectPacketSize( &connectInfo,
- NULL,
- &remainingLength,
- &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Make sure buffer has enough space. */
- TEST_ASSERT_GREATER_OR_EQUAL( packetSize, networkBuffer.size );
- mqttStatus = MQTT_SerializeConnect( &connectInfo, NULL,
- remainingLength, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- verifySerializedConnectPacket( &connectInfo, NULL,
- remainingLength, &networkBuffer );
+ /* Should succeed in skipping even if value is semantically invalid */
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 2, currentIndex );
}
-/* ================== Testing MQTT_SerializeDisconnect ===================== */
-
/**
- * @brief Call Mqtt_SerializeDisconnect using a NULL pBuffer and an insufficient
- * buffer size in order to receive MQTTBadParameter and MQTTNoMemory errors.
+ * @brief Test skipping property with maximum UTF-8 string length.
*/
-void test_MQTT_SerializeDisconnect_Invalid_Params()
+void test_MQTT_SkipNextProperty_MaxUtf8Length( void )
{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- size_t packetSize = 0;
- MQTTFixedBuffer_t networkBuffer;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
- /* Test NULL pFixedBuffer. */
- mqttStatus = MQTT_SerializeDisconnect( NULL );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Test a NULL pFixedBuffer->pBuffer. */
- networkBuffer.pBuffer = NULL;
- mqttStatus = MQTT_SerializeDisconnect( &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ *pIndex++ = MQTT_AUTH_METHOD_ID;
+ *pIndex++ = 0xFF;
+ *pIndex++ = 0xFF; /* Length = 65535 (max) */
- /* Test disconnectPacketSize > pFixedBuffer->size. */
- /* Get MQTT disconnect packet size and remaining length. */
- mqttStatus = MQTT_GetDisconnectPacketSize( &packetSize );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- networkBuffer.pBuffer = mqttBuffer;
- networkBuffer.size = packetSize - 1;
- mqttStatus = MQTT_SerializeDisconnect( &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTNoMemory, mqttStatus );
+ /* Set buffer to accommodate this */
+ propBuilder.currentIndex = 3;
+ propBuilder.bufferLength = 3;
+
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+
+ /* Should fail due to insufficient buffer */
+ TEST_ASSERT_EQUAL( MQTTBadResponse, status );
}
/**
- * @brief This method calls MQTT_SerializeDisconnect successfully in order to
- * get full coverage on the method.
+ * @brief Test skipping all property types in one buffer.
*/
-void test_MQTT_SerializeDisconnect_Happy_Path()
+void test_MQTT_SkipNextProperty_AllPropertyTypes( void )
{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- MQTTFixedBuffer_t networkBuffer;
+ uint8_t testBuffer[ MQTT_TEST_BUFFER_LENGTH ];
+ MQTTPropBuilder_t propBuilder = { 0 };
+ MQTTStatus_t status;
+ size_t currentIndex = 0;
+ uint8_t * pIndex = testBuffer;
+ uint32_t expectedIndex;
- /* Fill structs to pass into methods to be tested. */
- setupNetworkBuffer( &networkBuffer );
+ propBuilder.pBuffer = testBuffer;
+ propBuilder.bufferLength = MQTT_TEST_BUFFER_LENGTH;
- /* Make sure buffer has enough space. */
- mqttStatus = MQTT_SerializeDisconnect( &networkBuffer );
- TEST_ASSERT_EQUAL( MQTT_PACKET_TYPE_DISCONNECT, networkBuffer.pBuffer[ 0 ] );
- TEST_ASSERT_EQUAL( MQTT_DISCONNECT_REMAINING_LENGTH, networkBuffer.pBuffer[ 1 ] );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-}
+ /* Add one of each type */
-/* ================== Testing MQTT_UpdateDuplicatePublishFlag ===================== */
+ /* 4-byte integer */
+ *pIndex++ = MQTT_SESSION_EXPIRY_ID;
+ *pIndex++ = UINT32_BYTE3( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE2( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE1( MQTT_TEST_UINT32 );
+ *pIndex++ = UINT32_BYTE0( MQTT_TEST_UINT32 );
+ expectedIndex = 5;
-/**
- * @brief Call MQTT_UpdateDuplicatePublishFlag using a NULL pHeader and a header that does
- * not come from a publish packet, in order to receive MQTTBadParameter errors.
- */
-void test_MQTT_UpdateDuplicatePublishFlag_Invalid_Params()
-{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- uint8_t pHeader = MQTT_PACKET_TYPE_SUBSCRIBE;
+ /* 2-byte integer */
+ *pIndex++ = MQTT_RECEIVE_MAX_ID;
+ *pIndex++ = UINT16_HIGH_BYTE( MQTT_TEST_UINT16 );
+ *pIndex++ = UINT16_LOW_BYTE( MQTT_TEST_UINT16 );
- /* Test NULL pHeader. */
- mqttStatus = MQTT_UpdateDuplicatePublishFlag( NULL, true );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ /* 1-byte integer */
+ *pIndex++ = MQTT_MAX_QOS_ID;
+ *pIndex++ = MQTT_TEST_UINT8;
- /* Test a non-publish header. */
- mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, true );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
+ /* UTF-8 string */
+ *pIndex++ = MQTT_AUTH_METHOD_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
-/**
- * @brief This method calls MQTT_UpdateDuplicatePublishFlag successfully in order to
- * get full coverage on the method.
- */
-void test_MQTT_UpdateDuplicatePublishFlag_Happy_Path()
-{
- MQTTStatus_t mqttStatus = MQTTSuccess;
- uint8_t pHeader = MQTT_PACKET_TYPE_PUBLISH;
+ /* User property */
+ *pIndex++ = MQTT_USER_PROPERTY_ID;
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
+ pIndex += encodeStringUT( pIndex, MQTT_TEST_UTF8_STRING, MQTT_TEST_UTF8_STRING_LENGTH );
- /* Test to set the flag. */
- mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, true );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- TEST_ASSERT_NOT_EQUAL_INT( ( pHeader ) & ( 0x01U << ( 3 ) ), 0 );
+ /* Variable byte integer */
+ *pIndex++ = MQTT_SUBSCRIPTION_ID_ID;
+ *pIndex++ = 0x7F;
- /* Test to clear the flag. */
- mqttStatus = MQTT_UpdateDuplicatePublishFlag( &pHeader, false );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- TEST_ASSERT_EQUAL_INT( ( pHeader ) & ( 0x01U << ( 3 ) ), 0 );
-}
+ propBuilder.currentIndex = ( uint32_t ) ( pIndex - testBuffer );
-/* ========================================================================== */
+ /* Skip first property and verify */
+ status = MQTT_SkipNextProperty( &propBuilder, ¤tIndex );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( expectedIndex, currentIndex );
+}
diff --git a/test/unit-test/core_mqtt_state_utest.c b/test/unit-test/core_mqtt_state_utest.c
index fd04d1523..7e5aa76fe 100644
--- a/test/unit-test/core_mqtt_state_utest.c
+++ b/test/unit-test/core_mqtt_state_utest.c
@@ -92,13 +92,21 @@ static uint32_t getTime( void )
* @param[in] pPacketInfo Packet Info pointer for the incoming packet.
* @param[in] pDeserializedInfo Deserialized information from the incoming packet.
*/
-static void eventCallback( MQTTContext_t * pContext,
+static bool eventCallback( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
- MQTTDeserializedInfo_t * pDeserializedInfo )
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
( void ) pPacketInfo;
( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
+
+ return true;
}
static void resetPublishRecords( MQTTContext_t * pMqttContext )
@@ -171,14 +179,15 @@ void test_MQTT_ReserveState( void )
MQTTPubAckInfo_t incomingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
-
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* QoS 0 returns success. */
@@ -379,13 +388,16 @@ void test_MQTT_ReserveState_compactRecords( void )
MQTTPubAckInfo_t incomingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* Consider the state of the array with 2 states. 1 indicates a non empty
@@ -555,13 +567,16 @@ void test_MQTT_UpdateStatePublish( void )
MQTTPubAckInfo_t incomingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* QoS 0. */
@@ -764,14 +779,15 @@ void test_MQTT_UpdateStateAck( void )
MQTTPubAckInfo_t incomingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ MQTT_STATE_ARRAY_MAX_COUNT ] = { 0 };
-
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* NULL parameters. */
@@ -959,13 +975,16 @@ void test_MQTT_AckToResend( void )
transport.recv = transportRecvSuccess;
transport.send = transportSendSuccess;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
/* Invalid parameters. */
@@ -1054,14 +1073,15 @@ void test_MQTT_PublishToResend( void )
transport.send = transportSendSuccess;
MQTTFixedBuffer_t networkBuffer = { 0 };
-
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
status = MQTT_Init( &mqttContext, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
status = MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, MQTT_STATE_ARRAY_MAX_COUNT,
- incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT );
+ incomingRecords, MQTT_STATE_ARRAY_MAX_COUNT, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
diff --git a/test/unit-test/core_mqtt_utest.c b/test/unit-test/core_mqtt_utest.c
index c3ce86ba8..c89f1a985 100644
--- a/test/unit-test/core_mqtt_utest.c
+++ b/test/unit-test/core_mqtt_utest.c
@@ -33,75 +33,71 @@
#include "unity.h"
/* Include paths for public enums, structures, and macros. */
-#include "core_mqtt.h"
-
#include "mock_core_mqtt_serializer.h"
+#include "mock_core_mqtt_serializer_private.h"
#include "mock_core_mqtt_state.h"
-
#include "core_mqtt_config_defaults.h"
+#include "core_mqtt.h"
+
/* Set network context to double pointer to buffer (uint8_t**). */
struct NetworkContext
{
uint8_t ** buffer;
};
+static MQTTStatus_t validateSubscribeReturn = MQTTSuccess;
+
/**
* @brief MQTT client identifier.
*/
-#define MQTT_CLIENT_IDENTIFIER "testclient"
+#define MQTT_CLIENT_IDENTIFIER "testclient"
/**
* @brief A valid starting packet ID per MQTT spec. Start from 1.
*/
-#define MQTT_FIRST_VALID_PACKET_ID ( 1 )
+#define MQTT_FIRST_VALID_PACKET_ID ( 1 )
/**
- * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 3.1.1 spec.
+ * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 5.0 spec.
*/
-#define MQTT_PACKET_PINGREQ_SIZE ( 2U )
+#define MQTT_PACKET_PINGREQ_SIZE ( 2U )
/**
* @brief A packet type not handled by MQTT_ProcessLoop.
*/
-#define MQTT_PACKET_TYPE_INVALID ( 0U )
+#define MQTT_PACKET_TYPE_INVALID ( 0U )
/**
* @brief Number of milliseconds in a second.
*/
-#define MQTT_ONE_SECOND_TO_MS ( 1000U )
+#define MQTT_ONE_SECOND_TO_MS ( 1000U )
/**
* @brief Length of the MQTT network buffer.
*/
-#define MQTT_TEST_BUFFER_LENGTH ( 128 )
+#define MQTT_TEST_BUFFER_LENGTH ( 128 )
/**
* @brief Sample keep-alive interval that should be greater than 0.
*/
-#define MQTT_SAMPLE_KEEPALIVE_INTERVAL_S ( 1U )
-
-/**
- * @brief Length of time spent for single test case with
- * multiple iterations spent in the process loop for coverage.
- */
-#define MQTT_SAMPLE_PROCESS_LOOP_TIMEOUT_MS ( 1U )
+#define MQTT_SAMPLE_KEEPALIVE_INTERVAL_S ( 1U )
/**
* @brief Zero timeout in the process loop implies one iteration.
*/
-#define MQTT_NO_TIMEOUT_MS ( 0U )
+#define MQTT_NO_TIMEOUT_MS ( 0U )
/**
* @brief Sample length of remaining serialized data.
*/
-#define MQTT_SAMPLE_REMAINING_LENGTH ( 64 )
+#define MQTT_SAMPLE_REMAINING_LENGTH ( 64 )
/**
* @brief Subtract this value from max value of global entry time
* for the timer overflow test.
*/
-#define MQTT_OVERFLOW_OFFSET ( 3 )
+#define MQTT_OVERFLOW_OFFSET ( 3 )
/**
* @brief The number of times the "getTime()" function is called
@@ -115,57 +111,67 @@ struct NetworkContext
* This can change when the implementation changes which would be
* caught through unit test failure.
*/
-#define MQTT_TIMER_CALLS_PER_ITERATION ( 6 )
+#define MQTT_TIMER_CALLS_PER_ITERATION ( 6 )
/**
* @brief Timeout for the timer overflow test.
*/
-#define MQTT_TIMER_OVERFLOW_TIMEOUT_MS ( 10 )
+#define MQTT_TIMER_OVERFLOW_TIMEOUT_MS ( 10 )
/**
* @brief A sample network context that we set to NULL.
*/
-#define MQTT_SAMPLE_NETWORK_CONTEXT ( NULL )
+#define MQTT_SAMPLE_NETWORK_CONTEXT ( NULL )
/**
* @brief Sample topic filter to subscribe to.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER "iot"
+#define MQTT_SAMPLE_TOPIC_FILTER "iot"
/**
* @brief Length of sample topic filter.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH ( sizeof( MQTT_SAMPLE_TOPIC_FILTER ) - 1 )
+#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH ( sizeof( MQTT_SAMPLE_TOPIC_FILTER ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER1 "TopicFilter2"
+#define MQTT_SAMPLE_TOPIC_FILTER1 "TopicFilter2"
/**
* @brief Length of sample topic filter.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH1 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER1 ) - 1 )
+#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH1 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER1 ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER2 "SomeTopic"
+#define MQTT_SAMPLE_TOPIC_FILTER2 "SomeTopic"
/**
* @brief Length of sample topic filter.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH2 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER2 ) - 1 )
+#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH2 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER2 ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER3 "iotTopicFilter"
+#define MQTT_SAMPLE_TOPIC_FILTER3 "iotTopicFilter"
/**
* @brief Length of sample topic filter.
*/
-#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH3 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER3 ) - 1 )
+#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH3 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER3 ) - 1 )
+
+
+#define TEST_TOPIC_ALIAS ( 2U )
+#define TEST_MSG_EXPIRY ( 100U )
+#define TEST_CONTENT_TYPE_LENGTH ( 2 )
+#define TEST_CONTENT_TYPE ( "ab" )
+#define TEST_RESPONSE_TOPIC_LENGTH ( 10 )
+#define TEST_RESPONSE_TOPIC ( "aaaaaaaaaa" )
+#define TEST_CORRELATION_DATA_LENGTH ( 5 )
+#define TEST_CORRELATION_DATA ( "abcde" )
/**
* @brief Return values of mocked calls in MQTT_ProcessLoop(). Used by
@@ -193,19 +199,6 @@ struct MQTTVec
size_t vectorLen; /**< Length of the transport vector. USER SHOULD NOT ACCESS THIS DIRECTLY - IT IS AN INTERNAL DETAIL AND CAN CHANGE. */
};
-/**
- * @brief The packet type to be received by the process loop.
- * IMPORTANT: Make sure this is set before calling expectProcessLoopCalls(...).
- */
-static uint8_t currentPacketType = MQTT_PACKET_TYPE_INVALID;
-
-/**
- * @brief The return value of modifyIncomingPacket(...) CMock callback that
- * replaces a call to MQTT_GetIncomingPacketTypeAndLength.
- * IMPORTANT: Make sure this is set before calling expectProcessLoopCalls(...).
- */
-static MQTTStatus_t modifyIncomingPacketStatus = MQTTSuccess;
-
/**
* @brief Time at the beginning of each test. Note that this is not updated with
* a real clock. Instead, we simply increment this variable.
@@ -233,6 +226,7 @@ static size_t publishCopyBufferSize = 0;
*/
static bool isEventCallbackInvoked = false;
static bool receiveOnce = false;
+static MQTTStatus_t modifyIncomingPacketStatus = MQTTSuccess;
static const uint8_t SubscribeHeader[] =
{
@@ -252,6 +246,7 @@ static const uint8_t UnsubscribeHeader[] =
};
static const size_t UnsubscribeHeaderLength = 5U;
+
/* ============================ UNITY FIXTURES ============================ */
/* Called before each test method. */
@@ -280,9 +275,6 @@ int suiteTearDown( int numFailures )
return numFailures;
}
-
-/* ========================================================================== */
-
/**
* @brief Mock successful transport send, and write data into buffer for
* verification.
@@ -308,35 +300,7 @@ static int32_t mockSend( NetworkContext_t * pNetworkContext,
return bytesToSend;
}
-/**
- * @brief Initialize pNetworkBuffer using static buffer.
- *
- * @param[in] pNetworkBuffer Network buffer provided for the context.
- */
-static void setupNetworkBuffer( MQTTFixedBuffer_t * const pNetworkBuffer )
-{
- pNetworkBuffer->pBuffer = mqttBuffer;
- pNetworkBuffer->size = MQTT_TEST_BUFFER_LENGTH;
-}
-
-/**
- * @brief Mocked MQTT event callback.
- *
- * @param[in] pContext MQTT context pointer.
- * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
- * @param[in] pDeserializedInfo Deserialized information from the incoming packet.
- */
-static void eventCallback( MQTTContext_t * pContext,
- MQTTPacketInfo_t * pPacketInfo,
- MQTTDeserializedInfo_t * pDeserializedInfo )
-{
- ( void ) pContext;
- ( void ) pPacketInfo;
- ( void ) pDeserializedInfo;
-
- /* Update the global state to indicate that event callback is invoked. */
- isEventCallbackInvoked = true;
-}
+/* ========================================================================== */
/**
* @brief A mocked timer query function that increments on every call. This
@@ -378,213 +342,657 @@ static uint32_t getTimeMockBigTimeStep( void )
return globalEntryTime;
}
-
-/**
- * @brief A mocked timer function that could be used on a device with no system
- * time.
- */
-static uint32_t getTimeDummy( void )
-{
- return 0;
-}
-
/**
- * @brief Mocked successful transport writev.
- *
- * @param[in] tcpSocket TCP socket.
- * @param[in] pMessage vectors to send
- * @param[in] bytesToWrite number of vectors
+ * @brief Mocked MQTT event callback.
*
- * @return Number of bytes sent; negative value on error;
- * 0 for timeout or 0 bytes sent.
+ * @param[in] pContext MQTT context pointer.
+ * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
+ * @param[in] pDeserializedInfo Deserialized information from the incoming packet.
*/
-static int32_t transportWritevSuccess( NetworkContext_t * pNetworkContext,
- TransportOutVector_t * pIoVectorIterator,
- size_t vectorsToBeSent )
+static bool eventCallback( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
- TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
- int32_t bytesToWrite = 0;
- size_t i;
+ ( void ) pContext;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
- for( i = 0; i < vectorsToBeSent; ++i )
+ /* Update the global state to indicate that event callback is invoked. */
+ isEventCallbackInvoked = true;
+
+ if( pSendPropsBuffer != NULL )
{
- bytesToWrite += pIoVectorIterator->iov_len;
- pIoVectorIterator++;
+ pSendPropsBuffer->pBuffer = NULL;
}
- return bytesToWrite;
+ return true;
}
/**
- * @brief Mocked successful publish store function.
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- * @param[in] pIoVec array of transportout vectors
- * @param[in] ioVecCount number of vectors in the array
+ * @brief Mocked MQTT event callback.
*
- * @return true if store is successful else false
+ * @param[in] pContext MQTT context pointer.
+ * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
+ * @param[in] pDeserializedInfo Deserialized information from the incoming packet.
*/
-bool publishStoreCallbackSuccess( struct MQTTContext * pContext,
- uint16_t packetId,
- MQTTVec_t * pMqttVec )
+
+MQTTReasonCodeInfo_t GlobalAckInfo;
+
+
+static bool eventCallback2( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
- ( void ) pMqttVec;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pGetPropsBuffer;
+
+
+ uint8_t buf[ 13 ];
+ buf[ 0 ] = 0x26;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x02;
+ buf[ 3 ] = 'a';
+ buf[ 4 ] = 'b';
+ buf[ 5 ] = 0x00;
+ buf[ 6 ] = 0x02;
+ buf[ 7 ] = 'c';
+ buf[ 8 ] = 'd';
+ buf[ 9 ] = 0x1F;
+ buf[ 10 ] = 0x00;
+ buf[ 11 ] = 0x01;
+ buf[ 12 ] = 'e';
+
+ *pReasonCode = MQTT_REASON_PUBREC_SUCCESS;
+
+ if( pSendPropsBuffer != NULL )
+ {
+ pSendPropsBuffer->pBuffer = buf;
+ pSendPropsBuffer->currentIndex = 13;
+ }
+
+ isEventCallbackInvoked = true;
return true;
}
-
-/**
- * @brief Mocked failed publish store function.
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- * @param[in] pIoVec array of transportout vectors
- * @param[in] ioVecCount number of vectors in the array
- *
- * @return true if store is successful else false
- */
-bool publishStoreCallbackFailed( struct MQTTContext * pContext,
- uint16_t packetId,
- MQTTVec_t * pMqttVec )
+static bool eventCallback3( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
- ( void ) pMqttVec;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
- return false;
+ isEventCallbackInvoked = true;
+
+ *pReasonCode = MQTT_REASON_PUBREC_NO_MATCHING_SUBSCRIBERS;
+
+ if( pSendPropsBuffer != NULL )
+ {
+ pSendPropsBuffer->pBuffer = NULL;
+ pSendPropsBuffer->currentIndex = 0;
+ }
+
+ pDeserializedInfo->packetIdentifier = 0;
+
+ return true;
}
-/**
- * @brief Mocked successful publish retrieve function.
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- * @param[in] pIoVec array of transportout vectors
- * @param[in] ioVecCount number of vectors in the array
- *
- * @return true if retrieve is successful else false
- */
-bool publishRetrieveCallbackSuccess( struct MQTTContext * pContext,
- uint16_t packetId,
- uint8_t ** pPacket,
- size_t * pPacketSize )
+static bool eventCallbackInvalidRC( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
- *pPacket = publishCopyBuffer;
- *pPacketSize = publishCopyBufferSize;
+ isEventCallbackInvoked = true;
+
+ *pReasonCode = MQTT_REASON_SUBACK_GRANTED_QOS1;
+ uint8_t buf[ 13 ];
+ buf[ 0 ] = 0x26;
+ buf[ 1 ] = 0x00;
+ buf[ 2 ] = 0x02;
+ buf[ 3 ] = 'a';
+ buf[ 4 ] = 'b';
+ buf[ 5 ] = 0x00;
+ buf[ 6 ] = 0x02;
+ buf[ 7 ] = 'c';
+ buf[ 8 ] = 'd';
+ buf[ 9 ] = 0x1F;
+ buf[ 10 ] = 0x00;
+ buf[ 11 ] = 0x01;
+ buf[ 12 ] = 'e';
+
+ if( pSendPropsBuffer != NULL )
+ {
+ pSendPropsBuffer->pBuffer = buf;
+ pSendPropsBuffer->currentIndex = 13;
+ }
+
+ pDeserializedInfo->packetIdentifier = 0;
return true;
}
/**
- * @brief Mocked publish retrieve function. Succeeds once then fails
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- * @param[in] pIoVec array of transportout vectors
- * @param[in] ioVecCount number of vectors in the array
+ * @brief Mocked MQTT event callback.
*
- * @return true if retrieve is successful else false
- */
-bool publishRetrieveCallbackSuccessThenFail( struct MQTTContext * pContext,
- uint16_t packetId,
- uint8_t ** pPacket,
- size_t * pPacketSize )
+ * @param[in] pContext MQTT context pointer.
+ * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
+ * @param[in] pDeserializedInfo Deserialized information from the incoming packet.\
+ * @param[out] pReasonCode Reason code for the event.
+ * @param[out] pSendPropsBuffer Buffer to store properties for the outgoing packet.
+ * @param[in] pGetPropsBuffer Buffer to get properties for the incoming packet.
+ */
+static bool eventCallback4( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
-
- bool ret = true;
- static int count = 0;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pGetPropsBuffer;
+ uint8_t buf[ 10 ];
- *pPacket = publishCopyBuffer;
- *pPacketSize = publishCopyBufferSize;
+ /* Update the global state to indicate that event callback is invoked. */
+ *pReasonCode = MQTT_REASON_PUBREL_PACKET_IDENTIFIER_NOT_FOUND;
+ isEventCallbackInvoked = true;
- if( count != 0 )
+ if( pSendPropsBuffer != NULL )
{
- count = 0;
- ret = false;
+ pSendPropsBuffer->pBuffer = buf;
+ pSendPropsBuffer->currentIndex = 0;
}
- count++;
-
- return ret;
+ return true;
}
/**
- * @brief Mocked failed publish retrieve function.
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- * @param[in] pIoVec array of transportout vectors
- * @param[in] ioVecCount number of vectors in the array
+ * @brief Mocked MQTT event callback that fails with a #MQTTEventCallbackFailed
*
- * @return true if retrieve is successful else false
+ * @param[in] pContext MQTT context pointer.
+ * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
+ * @param[in] pDeserializedInfo Deserialized information from the incoming packet.
+ * @param[out] pReasonCode Reason code for the event.
+ * @param[out] pSendPropsBuffer Buffer to store properties for the outgoing packet.
+ * @param[in] pGetPropsBuffer Buffer to get properties for the incoming packet.
*/
-bool publishRetrieveCallbackFailed( struct MQTTContext * pContext,
- uint16_t packetId,
- uint8_t ** pPacket,
- size_t * pPacketSize )
+static bool eventCallbackFail( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
- ( void ) pPacket;
- ( void ) pPacketSize;
-
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
+ isEventCallbackInvoked = true;
return false;
}
-/**
- * @brief Mocked publish clear function.
- *
- * @param[in] pContext initialised mqtt context.
- * @param[in] packetId packet id
- *
- * @return true if clear is successful else false
- */
-void publishClearCallback( struct MQTTContext * pContext,
- uint16_t packetId )
+static bool eventCallbackRetHugeBuffer( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
( void ) pContext;
- ( void ) packetId;
-}
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
+ isEventCallbackInvoked = true;
+ uint8_t buffer[ 10 ];
+ if( pSendPropsBuffer != NULL )
+ {
+ pSendPropsBuffer->pBuffer = buffer;
+ pSendPropsBuffer->currentIndex = MQTT_REMAINING_LENGTH_INVALID;
+ }
-static void verifyEncodedTopicString( TransportOutVector_t * pIoVectorIterator,
- char * pTopicFilter,
- size_t topicFilterLength,
- MQTTQoS_t topicQos,
- int32_t * pBytesToWrite )
+ return true;
+}
+
+static bool eventCallbackNopropsNoReason( MQTTContext_t * pContext,
+ MQTTPacketInfo_t * pPacketInfo,
+ MQTTDeserializedInfo_t * pDeserializedInfo,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ MQTTPropBuilder_t * pSendPropsBuffer,
+ MQTTPropBuilder_t * pGetPropsBuffer )
{
- /* Encoded topic length. */
- uint8_t serializedLength[ 2 ];
- const uint8_t * buffer;
- size_t length;
+ ( void ) pContext;
+ ( void ) pPacketInfo;
+ ( void ) pDeserializedInfo;
+ ( void ) pReasonCode;
+ ( void ) pSendPropsBuffer;
+ ( void ) pGetPropsBuffer;
+ isEventCallbackInvoked = true;
- serializedLength[ 0 ] = ( uint8_t ) ( topicFilterLength >> 8 );
- serializedLength[ 1 ] = ( uint8_t ) ( topicFilterLength & 0x00ffU );
+ if( pSendPropsBuffer != NULL )
+ {
+ pSendPropsBuffer->pBuffer = NULL;
+ pSendPropsBuffer->currentIndex = 0;
+ }
- buffer = pIoVectorIterator[ 0 ].iov_base;
- length = pIoVectorIterator[ 0 ].iov_len;
+ pDeserializedInfo->packetIdentifier = 0;
+ return true;
+}
- TEST_ASSERT_EQUAL( 2U, length );
- TEST_ASSERT_EQUAL_UINT8_ARRAY( serializedLength, buffer, 2U );
- ( *pBytesToWrite ) += length;
+static MQTTContext_t globalMQTTContext;
+static MQTTStatus_t MQTT_SerializeAck_SuccessAndSetDisconnect( const MQTTFixedBuffer_t * pFixedBuffer,
+ uint8_t packetType,
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pAckProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ int numcallbacks )
+{
+ ( void ) numcallbacks;
+ ( void ) pReasonCode;
+ ( void ) packetId;
+ ( void ) packetType;
+ ( void ) pAckProperties;
+ ( void ) pFixedBuffer;
- buffer = pIoVectorIterator[ 1 ].iov_base;
- length = pIoVectorIterator[ 1 ].iov_len;
+ globalMQTTContext.connectStatus = MQTTNotConnected;
- /* Encoded topic string. */
- TEST_ASSERT_EQUAL( topicFilterLength, length );
- TEST_ASSERT_EQUAL_UINT8_ARRAY( pTopicFilter, buffer, topicFilterLength );
- ( *pBytesToWrite ) += length;
+ return MQTTSuccess;
+}
- buffer = pIoVectorIterator[ 2 ].iov_base;
+static MQTTStatus_t MQTT_SerializeAck_SuccessAndSetDisconnPending( const MQTTFixedBuffer_t * pFixedBuffer,
+ uint8_t packetType,
+ uint16_t packetId,
+ const MQTTPropBuilder_t * pAckProperties,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ int numcallbacks )
+{
+ ( void ) numcallbacks;
+ ( void ) pReasonCode;
+ ( void ) packetId;
+ ( void ) packetType;
+ ( void ) pAckProperties;
+ ( void ) pFixedBuffer;
+
+ globalMQTTContext.connectStatus = MQTTDisconnectPending;
+
+ return MQTTSuccess;
+}
+
+static uint8_t * MQTTV5_SerializeAckFixed_cb( uint8_t * pIndex,
+ uint8_t packetType,
+ uint16_t packetId,
+ uint32_t remainingLength,
+ MQTTSuccessFailReasonCode_t reasonCode,
+ int numcallbacks )
+{
+ ( void ) packetType;
+ ( void ) packetId;
+ ( void ) remainingLength;
+ ( void ) reasonCode;
+ ( void ) numcallbacks;
+
+ return pIndex;
+}
+
+static MQTTStatus_t decodeSubackPropertyLength_cb( const uint8_t * pIndex,
+ uint32_t remainingLength,
+ uint32_t * subackPropertyLength,
+ int numcallbacks )
+{
+ ( void ) pIndex;
+ ( void ) remainingLength;
+ ( void ) numcallbacks;
+ *subackPropertyLength = 1U;
+ return MQTTSuccess;
+}
+
+static MQTTStatus_t initConnectProperties_cb( MQTTConnectionProperties_t * pConnectProperties,
+ int numcallbacks )
+{
+ ( void ) numcallbacks;
+ pConnectProperties->receiveMax = UINT16_MAX;
+ pConnectProperties->maxPacketSize = MQTT_MAX_PACKET_SIZE;
+ pConnectProperties->requestProblemInfo = true;
+ pConnectProperties->serverReceiveMax = UINT16_MAX;
+ pConnectProperties->serverMaxQos = 1U;
+ pConnectProperties->serverMaxPacketSize = MQTT_MAX_PACKET_SIZE;
+ pConnectProperties->isWildcardAvailable = 1U;
+ pConnectProperties->isSubscriptionIdAvailable = 1U;
+ pConnectProperties->isSharedAvailable = 1U;
+ pConnectProperties->sessionExpiry = 0U;
+ pConnectProperties->topicAliasMax = 0U;
+ pConnectProperties->requestProblemInfo = true;
+ pConnectProperties->requestResponseInfo = false;
+ pConnectProperties->retainAvailable = 1U;
+ pConnectProperties->serverTopicAliasMax = 0U;
+ pConnectProperties->serverKeepAlive = UINT16_MAX;
+
+ return MQTTSuccess;
+}
+
+
+MQTTStatus_t MQTT_SerializeAck_StubSuccess( const MQTTFixedBuffer_t * pFixedBuffer,
+ uint8_t packetType,
+ uint16_t packetId )
+{
+ ( void ) pFixedBuffer;
+ ( void ) packetType;
+ ( void ) packetId;
+ return MQTTSuccess;
+}
+
+static uint8_t * MQTTV5_SerializeDisconnectFixed_cb( uint8_t * pIndex,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ int numcallbacks )
+{
+ ( void ) pIndex;
+ ( void ) pReasonCode;
+ ( void ) remainingLength;
+ ( void ) numcallbacks;
+
+ return pIndex;
+}
+
+/**
+ * @brief Mocked function to retrieve a function while setting the connectStatus to not connected.
+ *
+ * @param[in] pContext MQTT context pointer.
+ * @param[in] packetId Packet ID.
+ * @param[out] pSerializedMqttVec Pointer to serialized MQTT vector.
+ * @param[out] pSerializedMqttVecLen Length of serialized MQTT vector.
+ *
+ * @return Returns true.
+ */
+bool retrieveFunctionNotConnected( MQTTContext_t * pContext,
+ uint16_t packetId,
+ uint8_t ** pSerializedMqttVec,
+ size_t * pSerializedMqttVecLen )
+{
+ ( void ) packetId;
+ ( void ) pSerializedMqttVec;
+ ( void ) pSerializedMqttVecLen;
+ static uint8_t buf[ 10 ];
+ pContext->connectStatus = MQTTNotConnected;
+ *pSerializedMqttVec = buf;
+ *pSerializedMqttVecLen = 10;
+
+ return true;
+}
+
+
+
+/**
+ * @brief Mocked successful transport writev.
+ *
+ * @param[in] tcpSocket TCP socket.
+ * @param[in] pMessage vectors to send
+ * @param[in] bytesToWrite number of vectors
+ *
+ * @return Number of bytes sent; negative value on error;
+ * 0 for timeout or 0 bytes sent.
+ */
+static int32_t transportWritevSuccess( NetworkContext_t * pNetworkContext,
+ TransportOutVector_t * pIoVectorIterator,
+ size_t vectorsToBeSent )
+{
+ TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
+ int32_t bytesToWrite = 0;
+ size_t i;
+
+ for( i = 0; i < vectorsToBeSent; ++i )
+ {
+ bytesToWrite += pIoVectorIterator->iov_len;
+ pIoVectorIterator++;
+ }
+
+ return bytesToWrite;
+}
+
+static MQTTStatus_t MQTT_GetDisconnectPacketSize_ExpectReasonMalformed( const MQTTPropBuilder_t * pDisconnectProperties,
+ uint32_t * pRemainingLength,
+ uint32_t * pPacketSize,
+ uint32_t maxPacketSize,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ int numcallbacks )
+{
+ ( void ) pDisconnectProperties;
+ ( void ) maxPacketSize;
+ ( void ) numcallbacks;
+
+ TEST_ASSERT_NOT_NULL( pRemainingLength );
+ TEST_ASSERT_NOT_NULL( pPacketSize );
+ TEST_ASSERT_EQUAL_INT( MQTT_REASON_DISCONNECT_MALFORMED_PACKET, *pReasonCode );
+
+ *pPacketSize = 1U;
+ return MQTTSuccess;
+}
+
+static uint8_t * serializeDisconnectFixed_cb_OneByte( uint8_t * pIndex,
+ MQTTSuccessFailReasonCode_t * pReasonCode,
+ uint32_t remainingLength,
+ int numcallbacks )
+{
+ ( void ) pReasonCode;
+ ( void ) remainingLength;
+ ( void ) numcallbacks;
+
+ TEST_ASSERT_NOT_NULL( pIndex );
+ return &pIndex[ 1 ];
+}
+
+static uint8_t * encodeVariableLength_cb_1bytelength( uint8_t * pDestination,
+ uint32_t length,
+ int callCount )
+{
+ ( void ) length;
+ ( void ) callCount;
+
+ TEST_ASSERT_NOT_NULL( pDestination );
+
+ return &pDestination[ 1 ];
+}
+
+/**
+ * @brief Mocked successful publish store function.
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ * @param[in] pIoVec array of transportout vectors
+ * @param[in] ioVecCount number of vectors in the array
+ *
+ * @return true if store is successful else false
+ */
+static bool publishStoreCallbackSuccess( struct MQTTContext * pContext,
+ uint16_t packetId,
+ MQTTVec_t * pMqttVec )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+ ( void ) pMqttVec;
+
+ return true;
+}
+
+/**
+ * @brief Mocked failed publish store function.
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ * @param[in] pIoVec array of transportout vectors
+ * @param[in] ioVecCount number of vectors in the array
+ *
+ * @return true if store is successful else false
+ */
+static bool publishStoreCallbackFailed( struct MQTTContext * pContext,
+ uint16_t packetId,
+ MQTTVec_t * pMqttVec )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+ ( void ) pMqttVec;
+
+ return false;
+}
+
+/**
+ * @brief Mocked successful publish retrieve function.
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ * @param[in] pIoVec array of transportout vectors
+ * @param[in] ioVecCount number of vectors in the array
+ *
+ * @return true if retrieve is successful else false
+ */
+static bool publishRetrieveCallbackSuccess( struct MQTTContext * pContext,
+ uint16_t packetId,
+ uint8_t ** pPacket,
+ size_t * pPacketSize )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+
+ *pPacket = publishCopyBuffer;
+ *pPacketSize = publishCopyBufferSize;
+
+ return true;
+}
+
+/**
+ * @brief Mocked publish retrieve function. Succeeds once then fails
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ * @param[in] pIoVec array of transportout vectors
+ * @param[in] ioVecCount number of vectors in the array
+ *
+ * @return true if retrieve is successful else false
+ */
+static bool publishRetrieveCallbackSuccessThenFail( struct MQTTContext * pContext,
+ uint16_t packetId,
+ uint8_t ** pPacket,
+ size_t * pPacketSize )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+
+ bool ret = true;
+ static int count = 0;
+
+ *pPacket = publishCopyBuffer;
+ *pPacketSize = publishCopyBufferSize;
+
+ if( count != 0 )
+ {
+ count = 0;
+ ret = false;
+ }
+
+ count++;
+
+ return ret;
+}
+
+/**
+ * @brief Mocked failed publish retrieve function.
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ * @param[in] pIoVec array of transportout vectors
+ * @param[in] ioVecCount number of vectors in the array
+ *
+ * @return true if retrieve is successful else false
+ */
+static bool publishRetrieveCallbackFailed( struct MQTTContext * pContext,
+ uint16_t packetId,
+ uint8_t ** pPacket,
+ size_t * pPacketSize )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+ ( void ) pPacket;
+ ( void ) pPacketSize;
+
+ return false;
+}
+
+/**
+ * @brief Mocked publish clear function.
+ *
+ * @param[in] pContext initialised mqtt context.
+ * @param[in] packetId packet id
+ *
+ * @return true if clear is successful else false
+ */
+static void publishClearCallback( struct MQTTContext * pContext,
+ uint16_t packetId )
+{
+ ( void ) pContext;
+ ( void ) packetId;
+}
+
+static void verifyEncodedTopicString( TransportOutVector_t * pIoVectorIterator,
+ char * pTopicFilter,
+ size_t topicFilterLength,
+ MQTTQoS_t topicQos,
+ int32_t * pBytesToWrite )
+{
+ /* Encoded topic length. */
+ uint8_t serializedLength[ 2 ];
+ const uint8_t * buffer;
+ size_t length;
+
+ serializedLength[ 0 ] = ( uint8_t ) ( topicFilterLength >> 8 );
+ serializedLength[ 1 ] = ( uint8_t ) ( topicFilterLength & 0x00ffU );
+
+ buffer = pIoVectorIterator[ 0 ].iov_base;
+ length = pIoVectorIterator[ 0 ].iov_len;
+
+ TEST_ASSERT_EQUAL( 2U, length );
+ TEST_ASSERT_EQUAL_UINT8_ARRAY( serializedLength, buffer, 2U );
+ ( *pBytesToWrite ) += length;
+
+ buffer = pIoVectorIterator[ 1 ].iov_base;
+ length = pIoVectorIterator[ 1 ].iov_len;
+
+ /* Encoded topic string. */
+ TEST_ASSERT_EQUAL( topicFilterLength, length );
+ TEST_ASSERT_EQUAL_UINT8_ARRAY( pTopicFilter, buffer, topicFilterLength );
+ ( *pBytesToWrite ) += length;
+
+ buffer = pIoVectorIterator[ 2 ].iov_base;
length = pIoVectorIterator[ 2 ].iov_len;
/* Encoded QoS. */
@@ -646,7 +1054,7 @@ static int32_t transportWritevSubscribeSuccess( NetworkContext_t * pNetworkConte
/* The header. */
if( writeCount == 0 )
{
- TEST_ASSERT_EQUAL( 4, vectorsToBeSent );
+ TEST_ASSERT_EQUAL( 5, vectorsToBeSent );
buffer = pIoVectorIterator->iov_base;
length = pIoVectorIterator->iov_len;
@@ -656,8 +1064,17 @@ static int32_t transportWritevSubscribeSuccess( NetworkContext_t * pNetworkConte
bytesToWrite += length;
pIoVectorIterator++;
+ /* Property Length */
+ buffer = pIoVectorIterator[ 0 ].iov_base;
+ length = pIoVectorIterator[ 0 ].iov_len;
- /* First topic filter. */
+ TEST_ASSERT_EQUAL( 1, length );
+ TEST_ASSERT_EQUAL_UINT8( 0x00, *buffer );
+
+ bytesToWrite += length;
+ pIoVectorIterator++;
+
+ /* First topic filter. */
verifyEncodedTopicString( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
@@ -666,7 +1083,7 @@ static int32_t transportWritevSubscribeSuccess( NetworkContext_t * pNetworkConte
writeCount++;
- pIoVectorIterator += 4;
+ pIoVectorIterator += 3;
}
else if( writeCount == 1 )
{
@@ -735,7 +1152,7 @@ static int32_t transportWritevUnsubscribeSuccess( NetworkContext_t * pNetworkCon
/* The header. */
if( writeCount == 0 )
{
- TEST_ASSERT_EQUAL( 5, vectorsToBeSent );
+ TEST_ASSERT_EQUAL( 6, vectorsToBeSent );
buffer = pIoVectorIterator->iov_base;
length = pIoVectorIterator->iov_len;
@@ -746,6 +1163,15 @@ static int32_t transportWritevUnsubscribeSuccess( NetworkContext_t * pNetworkCon
bytesToWrite += length;
pIoVectorIterator++;
+ buffer = pIoVectorIterator[ 0 ].iov_base;
+ length = pIoVectorIterator[ 0 ].iov_len;
+
+ TEST_ASSERT_EQUAL( 1, length );
+ TEST_ASSERT_EQUAL_UINT8( 0x00, *buffer );
+
+ bytesToWrite += length;
+ pIoVectorIterator++;
+
/* First topic filter. */
verifyEncodedTopicStringUnsubscribe( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER,
@@ -858,6 +1284,7 @@ static int32_t transportSendFailure( NetworkContext_t * pNetworkContext,
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToWrite;
+ LogError( ( "transportSendFailure" ) );
return -1;
}
@@ -911,12 +1338,13 @@ static int32_t transportSendSucceedThenFailAfterConnect( NetworkContext_t * pNet
counter++;
- if( counter == 3 )
+ if( counter == 4 )
{
retVal = -1;
counter = 0;
}
+ LogError( ( "transportSendSucceedThenFailAfterConnect: %d", retVal ) );
return retVal;
}
@@ -1008,19 +1436,6 @@ static int32_t transportRecvOneByte( NetworkContext_t * pNetworkContext,
return 1;
}
-/**
- * @brief Mocked transport returning zero bytes to simulate reception
- * of no data over network.
- */
-static int32_t transportRecvNoData( NetworkContext_t * pNetworkContext,
- void * pBuffer,
- size_t bytesToRead )
-{
- ( void ) pNetworkContext;
- ( void ) pBuffer;
- ( void ) bytesToRead;
- return 0;
-}
/**
* @brief Initialize the transport interface with the mocked functions for
@@ -1037,15 +1452,33 @@ static void setupTransportInterface( TransportInterface_t * pTransport )
}
/**
- * @brief Initialize pSubscribeInfo using test-defined macros.
+ * @brief Initialize pNetworkBuffer using static buffer.
*
- * @param[in] pSubscribeInfo Pointer to MQTT subscription info.
+ * @param[in] pNetworkBuffer Network buffer provided for the context.
*/
-static void setupSubscriptionInfo( MQTTSubscribeInfo_t * pSubscribeInfo )
+static void setupNetworkBuffer( MQTTFixedBuffer_t * const pNetworkBuffer )
{
- pSubscribeInfo->qos = MQTTQoS1;
- pSubscribeInfo->pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
- pSubscribeInfo->topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
+ pNetworkBuffer->pBuffer = mqttBuffer;
+ pNetworkBuffer->size = MQTT_TEST_BUFFER_LENGTH;
+}
+
+static int32_t transportRecvNoData( NetworkContext_t * pNetworkContext,
+ void * pBuffer,
+ size_t bytesToRead )
+{
+ ( void ) pNetworkContext;
+ ( void ) pBuffer;
+ ( void ) bytesToRead;
+ return 0;
+}
+
+/**
+ * @brief A mocked timer function that could be used on a device with no system
+ * time.
+ */
+static uint32_t getTimeDummy( void )
+{
+ return 0;
}
/**
@@ -1066,6 +1499,22 @@ static void resetProcessLoopParams( ProcessLoopReturns_t * pExpectParams )
pExpectParams->timeoutMs = MQTT_NO_TIMEOUT_MS;
}
+/**
+ * @brief create default ackPropsBuilder
+ *
+ * @param[out] pAckPropsBuilder ackPropsBuilder to initialize
+ */
+static void setupackPropsBuilder( MQTTPropBuilder_t * pAckPropsBuilder )
+{
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ pAckPropsBuilder->pBuffer = ackPropsBuf;
+ pAckPropsBuilder->currentIndex = 0;
+ pAckPropsBuilder->bufferLength = ackPropsBufLength;
+ pAckPropsBuilder->fieldSet = 0;
+}
+
/**
* @brief create default context
*
@@ -1084,21 +1533,29 @@ static void setUPContext( MQTTContext_t * mqttContext )
memset( mqttContext, 0x0, sizeof( MQTTContext_t ) );
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
mqttStatus = MQTT_Init( mqttContext,
&transport,
getTime,
eventCallback,
&networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ mqttContext->ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_InitStatefulQoS( mqttContext,
outgoingRecords,
10,
incomingRecords,
- 10 );
+ 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
+uint8_t currentPacketType;
+
/**
* @brief This helper function is used to expect any calls from the process loop
* to mocked functions belonging to an external header file. Its parameters
@@ -1109,7 +1566,7 @@ static void expectProcessLoopCalls( MQTTContext_t * const pContext,
{
MQTTStatus_t mqttStatus = MQTTSuccess;
MQTTPacketInfo_t incomingPacket = { 0 };
- size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+ uint32_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
bool expectMoreCalls = true;
/* Copy values passed in the parameter struct. */
MQTTStatus_t deserializeStatus = pExpectParams->deserializeStatus;
@@ -1182,6 +1639,14 @@ static void expectProcessLoopCalls( MQTTContext_t * const pContext,
MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( pPubInfo );
}
}
+ else if( currentPacketType == MQTT_PACKET_TYPE_PINGRESP )
+ {
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( deserializeStatus );
+ }
+ else if( ( currentPacketType == MQTT_PACKET_TYPE_SUBACK ) || ( currentPacketType == MQTT_PACKET_TYPE_UNSUBACK ) )
+ {
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( deserializeStatus );
+ }
else
{
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( deserializeStatus );
@@ -1237,7 +1702,17 @@ static void expectProcessLoopCalls( MQTTContext_t * const pContext,
/* Serialize the packet to be sent in response to the received packet. */
if( expectMoreCalls )
{
- MQTT_SerializeAck_ExpectAnyArgsAndReturn( serializeStatus );
+ if( ( updateStateStatus != MQTTStateCollision ) && ( pContext->ackPropsBuffer.pBuffer != NULL ) )
+ {
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( serializeStatus );
+ }
+ else
+ {
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( serializeStatus );
+ }
if( serializeStatus != MQTTSuccess )
{
@@ -1293,6 +1768,7 @@ void test_MQTT_Init_Happy_Path( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_EQUAL( MQTTNotConnected, context.connectStatus );
@@ -1318,28 +1794,35 @@ void test_MQTT_Init_Invalid_Params( void )
setupNetworkBuffer( &networkBuffer );
/* Check that MQTTBadParameter is returned if any NULL parameters are passed. */
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( NULL, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, NULL, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Test if NULL is passed for any of the function pointers. */
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, NULL, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, NULL, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
transport.recv = NULL;
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
transport.recv = transportRecvSuccess;
transport.send = NULL;
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
@@ -1383,7 +1866,6 @@ void test_MQTT_CheckConnectStatus_return_correct_status( void )
TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
-
/* ========================================================================== */
/**
@@ -1423,11 +1905,11 @@ void test_MQTT_InitRetransmits_Invalid_Params( void )
/* ========================================================================== */
-static uint8_t * MQTT_SerializeConnectFixedHeader_cb( uint8_t * pIndex,
- const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
- int numcallbacks )
+static uint8_t * serializeConnectFixedHeader_cb( uint8_t * pIndex,
+ const MQTTConnectInfo_t * pConnectInfo,
+ const MQTTPublishInfo_t * pWillInfo,
+ uint32_t remainingLength,
+ int numcallbacks )
{
( void ) pConnectInfo;
( void ) pWillInfo;
@@ -1449,23 +1931,25 @@ void test_MQTT_Connect_sendConnect_already_connected( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* set MQTT Connection status as connected*/
mqttContext.connectStatus = MQTTConnected;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTStatusConnected, status );
}
@@ -1482,23 +1966,24 @@ void test_MQTT_Connect_sendConnect_disconnect_pending( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- /* set MQTT Connection status as connected*/
+ /* Set MQTT Connection status as pending disconnect. */
mqttContext.connectStatus = MQTTDisconnectPending;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTStatusDisconnectPending, status );
}
@@ -1515,30 +2000,37 @@ void test_MQTT_Connect_sendConnect_writev_error( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
setupTransportInterface( &transport );
transport.writev = transportWritevError;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
+
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
@@ -1551,26 +2043,30 @@ void test_MQTT_Connect_sendConnect1( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
setupTransportInterface( &transport );
transport.writev = NULL;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -1587,8 +2083,8 @@ void test_MQTT_Connect_WillInfoWrong( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
@@ -1597,18 +2093,20 @@ void test_MQTT_Connect_WillInfoWrong( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0, sizeof( MQTTPublishInfo_t ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -1625,14 +2123,15 @@ void test_MQTT_Connect_sendConnect2( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
setupTransportInterface( &transport );
- transport.writev = transportWritevFail;
+ transport.writev = NULL;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
@@ -1644,15 +2143,17 @@ void test_MQTT_Connect_sendConnect2( void )
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
mqttContext.transportInterface.writev = NULL;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -1669,8 +2170,8 @@ void test_MQTT_Connect_ProperWIllInfo( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
@@ -1690,6 +2191,7 @@ void test_MQTT_Connect_ProperWIllInfo( void )
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
@@ -1700,15 +2202,17 @@ void test_MQTT_Connect_ProperWIllInfo( void )
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -1725,8 +2229,8 @@ void test_MQTT_Connect_ProperWIllInfoWithNoPayload( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
@@ -1744,6 +2248,7 @@ void test_MQTT_Connect_ProperWIllInfoWithNoPayload( void )
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
@@ -1754,15 +2259,17 @@ void test_MQTT_Connect_ProperWIllInfoWithNoPayload( void )
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -1780,8 +2287,8 @@ void test_MQTT_Connect_ProperWIllInfoWithPayloadButZeroLength( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
@@ -1801,6 +2308,7 @@ void test_MQTT_Connect_ProperWIllInfoWithPayloadButZeroLength( void )
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
@@ -1811,28 +2319,26 @@ void test_MQTT_Connect_ProperWIllInfoWithPayloadButZeroLength( void )
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
-/**
- * @brief Test MQTT_Connect, except for receiving the CONNACK.
- */
-void test_MQTT_Connect_sendConnect3( void )
+void test_MQTT_Connect3()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
- uint32_t timeout = 2;
- bool sessionPresent;
+ bool sessionPresent = false;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
@@ -1841,18 +2347,13 @@ void test_MQTT_Connect_sendConnect3( void )
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- /* Empty connect info fails. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* No connect Properties */
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
- memset( &connectInfo, 0x0, sizeof( connectInfo ) );
-
- status = MQTT_Connect( &mqttContext,
- &connectInfo,
- NULL,
- timeout,
- &sessionPresent );
-
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -1873,16 +2374,17 @@ void test_MQTT_Connect_sendConnect4( void )
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Check parameters */
- status = MQTT_Connect( NULL, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( NULL, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_Connect( &mqttContext, NULL, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, NULL, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, NULL );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, NULL, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -1898,27 +2400,31 @@ void test_MQTT_Connect_sendConnect5( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t remainingLength;
- size_t packetSize;
+ uint32_t remainingLength;
+ uint32_t packetSize;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Send the CONNECT successfully. This provides branch coverage for sendPacket. */
mqttContext.transportInterface.send = transportSendSuccess;
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
/* We know the send was successful if MQTT_GetIncomingPacketTypeAndLength()
* is called. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTRecvFailed );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
}
@@ -1940,23 +2446,192 @@ void test_MQTT_Connect_sendConnect6( void )
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
connectInfo.pClientIdentifier = MQTT_CLIENT_IDENTIFIER;
connectInfo.clientIdentifierLength = sizeof( MQTT_CLIENT_IDENTIFIER ) - 1;
+ MQTTPropAdd_MaxPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( 2 );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
}
-/**
- * @brief Test CONNACK reception in MQTT_Connect.
- */
+void test_MQTT_Connect_error_path()
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTPublishInfo_t willInfo = { 0 };
+ uint32_t timeout = 2;
+ bool sessionPresent;
+ uint32_t receiveMax = 128;
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &willInfo, 0x0, sizeof( MQTTPublishInfo_t ) );
+ memset( &connectInfo, 0x0, sizeof( MQTTConnectInfo_t ) );
+
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+
+ /* With non-NULL Will. */
+ mqttContext.connectStatus = MQTTNotConnected;
+ mqttContext.keepAliveIntervalSec = 0;
+
+ MQTTPropBuilder_t propBuilder = { 0 };
+ uint8_t buf[ 500 ];
+ size_t bufLength = sizeof( buf );
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+
+ propBuilder.currentIndex = 200;
+
+ MQTTPropBuilder_t willPropsBuilder = { 0 };
+ uint8_t wbuf[ 500 ];
+ size_t wbufLength = sizeof( wbuf );
+ willPropsBuilder.pBuffer = wbuf;
+ willPropsBuilder.bufferLength = wbufLength;
+
+ willPropsBuilder.currentIndex = 10;
+
+ willInfo.pTopicName = "test";
+ willInfo.topicNameLength = 4;
+ willInfo.pPayload = "Payload";
+ willInfo.payloadLength = 7;
+
+ connectInfo.pUserName = "abcd";
+ connectInfo.userNameLength = 3;
+ connectInfo.passwordLength = 4;
+ connectInfo.pPassword = "1234";
+ mqttContext.transportInterface.send = transportSendSuccess;
+ MQTT_ValidateWillProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ MQTT_ValidateConnectProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ValidateConnectProperties_ReturnThruPtr_pPacketSizeMaxValue( &receiveMax );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
+ MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ updateContextWithConnectProps_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTRecvFailed );
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, &propBuilder, &willPropsBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
+
+ MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTRecvFailed );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
+
+ MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTRecvFailed );
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
+
+ status = MQTT_Connect( NULL, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ willInfo.pTopicName = NULL;
+ mqttContext.transportInterface.send = transportSendSuccess;
+ MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+void test_MQTT_Connect_UncleanSessionIncorrectState( void )
+{
+ bool sessionPresent = true;
+ MQTTStatus_t status;
+ MQTTPublishState_t pubRelState = MQTTPubRelSend;
+ MQTTConnectInfo_t connectInfo = { 0 };
+ uint32_t timeout = 2;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ memset( &globalMQTTContext, 0x0, sizeof( globalMQTTContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
+ MQTT_Init( &globalMQTTContext, &transport, getTime, eventCallback, &networkBuffer );
+
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
+ MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
+ connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
+
+ /* Test 1. No packets to resend reestablishing a session. */
+ /* successful receive CONNACK packet. */
+ incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
+ incomingPacket.remainingLength = 2;
+
+ /* Test case when broker sends session present flag. */
+ globalMQTTContext.transportInterface.recv = transportRecvSuccess;
+ connectInfo.cleanSession = false;
+ globalMQTTContext.transportInterface.send = transportSendSuccess;
+
+ /* One packet found in ack pending state with valid packet ID but invalid state, Sent
+ * PUBREL successfully. */
+ globalMQTTContext.connectStatus = MQTTNotConnected;
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( 1 );
+ MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
+
+ /* Serialize Ack successful. */
+ MQTT_SerializeAck_Stub( MQTT_SerializeAck_SuccessAndSetDisconnect );
+
+ /* Query for any remaining packets pending to ack - nothing to send. */
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
+
+ status = MQTT_Connect( &globalMQTTContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTStatusNotConnected, status );
+ TEST_ASSERT_EQUAL_INT( MQTTNotConnected, globalMQTTContext.connectStatus );
+
+ /* Check when the disconnect is pending. */
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( 1 );
+ MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
+
+ /* Serialize Ack successful. */
+ MQTT_SerializeAck_Stub( MQTT_SerializeAck_SuccessAndSetDisconnPending );
+
+ /* Query for any remaining packets pending to ack - nothing to send. */
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
+
+ status = MQTT_Connect( &globalMQTTContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTStatusDisconnectPending, status );
+ TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, globalMQTTContext.connectStatus );
+}
+
void test_MQTT_Connect_receiveConnack( void )
{
MQTTContext_t mqttContext = { 0 };
@@ -1966,6 +2641,7 @@ void test_MQTT_Connect_receiveConnack( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTConnectionProperties_t properties = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
@@ -1973,26 +2649,31 @@ void test_MQTT_Connect_receiveConnack( void )
transport.recv = transportRecvFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &properties, 0x0, sizeof( properties ) );
+
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Everything before receiving the CONNACK should succeed. */
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Nothing received from transport interface. Set timeout to 2 for branch coverage. */
timeout = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
+
/* Did not receive a CONNACK. */
incomingPacket.type = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.remainingLength = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Transport receive failure when receiving rest of packet. */
@@ -2002,15 +2683,14 @@ void test_MQTT_Connect_receiveConnack( void )
mqttContext.transportInterface.recv = transportRecvFailure;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
- /* Bad response when deserializing CONNACK. */
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Test case when broker sends session present flag in response to a
@@ -2020,9 +2700,9 @@ void test_MQTT_Connect_receiveConnack( void )
sessionPresentExpected = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
}
@@ -2045,10 +2725,11 @@ void test_MQTT_Connect_receiveConnack_retries( void )
transport.recv = transportRecvFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Everything before receiving the CONNACK should succeed. */
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Test with retries. MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT is 2.
@@ -2057,8 +2738,9 @@ void test_MQTT_Connect_receiveConnack_retries( void )
/* 2 retries. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
/* Did not receive a CONNACK. */
@@ -2066,7 +2748,7 @@ void test_MQTT_Connect_receiveConnack_retries( void )
incomingPacket.remainingLength = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Transport receive failure when receiving rest of packet. */
@@ -2074,22 +2756,18 @@ void test_MQTT_Connect_receiveConnack_retries( void )
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Bad response when deserializing CONNACK. */
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
}
-/**
- * @brief Test error cases for MQTT_Connect when a timeout occurs or the packet
- * needs to be discarded in MQTT_Connect.
- */
void test_MQTT_Connect_partial_receive( void )
{
MQTTContext_t mqttContext = { 0 };
@@ -2106,10 +2784,12 @@ void test_MQTT_Connect_partial_receive( void )
transport.recv = transportRecvNoData;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Everything before receiving the CONNACK should succeed. */
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
@@ -2118,8 +2798,10 @@ void test_MQTT_Connect_partial_receive( void )
* receive function always returns 0 bytes read. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Update to use mock receive function that receives one byte at a time for the
@@ -2132,8 +2814,8 @@ void test_MQTT_Connect_partial_receive( void )
incomingPacket.remainingLength = 3;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
- TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Discard packet, no timeout provided. This should fail since multiple
* iterations of the discard loop are required to discard the packet, but only
@@ -2141,7 +2823,7 @@ void test_MQTT_Connect_partial_receive( void )
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Timeout while discarding packet. */
@@ -2150,7 +2832,7 @@ void test_MQTT_Connect_partial_receive( void )
incomingPacket.remainingLength = 20;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Receive failure while discarding packet. */
@@ -2159,7 +2841,7 @@ void test_MQTT_Connect_partial_receive( void )
mqttContext.getTime = getTimeDummy;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, MQTT_NO_TIMEOUT_MS, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, MQTT_NO_TIMEOUT_MS, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
}
@@ -2184,9 +2866,10 @@ void test_MQTT_Connect_resendPendingAcks( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
@@ -2198,12 +2881,13 @@ void test_MQTT_Connect_resendPendingAcks( void )
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = true;
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* No packets to resend. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2215,14 +2899,14 @@ void test_MQTT_Connect_resendPendingAcks( void )
mqttContext.keepAliveIntervalSec = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack failure. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTBadParameter );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
@@ -2234,13 +2918,13 @@ void test_MQTT_Connect_resendPendingAcks( void )
mqttContext.transportInterface.send = transportSendFailure;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
@@ -2251,8 +2935,8 @@ void test_MQTT_Connect_resendPendingAcks( void )
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack successful. */
@@ -2260,7 +2944,7 @@ void test_MQTT_Connect_resendPendingAcks( void )
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2271,8 +2955,8 @@ void test_MQTT_Connect_resendPendingAcks( void )
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* First packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
@@ -2286,7 +2970,7 @@ void test_MQTT_Connect_resendPendingAcks( void )
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTBadParameter );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier + 2 );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
@@ -2295,8 +2979,8 @@ void test_MQTT_Connect_resendPendingAcks( void )
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* First packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
@@ -2311,48 +2995,124 @@ void test_MQTT_Connect_resendPendingAcks( void )
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
-}
-/**
- * @brief Test resend of publshes in MQTT_Connect.
- */
-void test_MQTT_Connect_resendUnAckedPublishes( void )
-{
- MQTTContext_t mqttContext = { 0 };
- MQTTConnectInfo_t connectInfo = { 0 };
- uint32_t timeout = 2;
- bool sessionPresent, sessionPresentResult;
- MQTTStatus_t status;
- TransportInterface_t transport = { 0 };
- MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTPacketInfo_t incomingPacket = { 0 };
- MQTTPubAckInfo_t incomingRecords = { 0 };
- MQTTPubAckInfo_t outgoingRecords = { 0 };
- uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ /* Test 7. One packet found in ack pending state. Sent PUBREL successfully
+ * for first but failed to update the state. */
+ mqttContext.connectStatus = MQTTNotConnected;
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ /* First packet. */
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
+ MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
+ /* Serialize Ack successful. */
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Failed to update the state. */
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
+ /* Second packet. */
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier + 1 );
+ MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
- publishCopyBuffer = localPublishCopyBuffer;
- publishCopyBufferSize = sizeof( "Hello world!" );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
- setupTransportInterface( &transport );
- setupNetworkBuffer( &networkBuffer );
+ /* Test 8: One publish found in ack pending state with valid packet ID but invalid state. */
+ mqttContext.connectStatus = MQTTNotConnected;
+ pubRelState = MQTTStateNull;
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- memset( &mqttContext, 0x0, sizeof( mqttContext ) );
- memset( &connectInfo, 0x00, sizeof( connectInfo ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
+ MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
+
+ /* Query for any remaining packets pending to ack - nothing to send. */
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
+ TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
+
+ /* Test 9: Success, non zero record count. */
+ MQTTPubAckInfo_t outgoingRecords, incomingRecords;
+ mqttContext.connectStatus = MQTTNotConnected;
+ mqttContext.outgoingPublishRecordMaxCount = 1;
+ mqttContext.incomingPublishRecordMaxCount = 1;
+ mqttContext.outgoingPublishRecords = &outgoingRecords;
+ mqttContext.incomingPublishRecords = &incomingRecords;
+ mqttContext.connectionProperties.receiveMax = 1;
+ mqttContext.connectionProperties.serverReceiveMax = 1;
+ pubRelState = MQTTStateNull;
+ sessionPresent = false;
+
+ memset( &outgoingRecords, 0xAB, sizeof( outgoingRecords ) );
+ memset( &incomingRecords, 0xAB, sizeof( incomingRecords ) );
+
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
+ TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
+
+ TEST_ASSERT_EACH_EQUAL_UINT8( 0, ( uint8_t * ) &incomingRecords, sizeof( incomingRecords ) );
+ TEST_ASSERT_EACH_EQUAL_UINT8( 0, ( uint8_t * ) &outgoingRecords, sizeof( outgoingRecords ) );
+}
+
+/**
+ * @brief Test resend of publshes in MQTT_Connect.
+ */
+void test_MQTT_Connect_resendUnAckedPublishes( void )
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ uint32_t timeout = 2;
+ bool sessionPresent, sessionPresentResult;
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 100 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ publishCopyBuffer = localPublishCopyBuffer;
+ publishCopyBufferSize = sizeof( "Hello world!" );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
@@ -2364,13 +3124,14 @@ void test_MQTT_Connect_resendUnAckedPublishes( void )
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = false;
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( 1 );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2390,6 +3151,8 @@ void test_MQTT_Connect_resendUnAckedPublishes2( void )
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
@@ -2399,17 +3162,18 @@ void test_MQTT_Connect_resendUnAckedPublishes2( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.clearFunction = publishClearCallback;
@@ -2422,14 +3186,15 @@ void test_MQTT_Connect_resendUnAckedPublishes2( void )
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = true;
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* No acks to resend. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
/* No publishes to resend. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2452,6 +3217,8 @@ void test_MQTT_Connect_resendUnAckedPublishes3( void )
MQTTPubAckInfo_t outgoingRecords = { 0 };
/* MQTTPublishState_t expectedState = { 0 }; */
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
@@ -2461,17 +3228,18 @@ void test_MQTT_Connect_resendUnAckedPublishes3( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
/* Test 4. One publish packet found to resend, but retrieve failed. */
@@ -2483,13 +3251,14 @@ void test_MQTT_Connect_resendUnAckedPublishes3( void )
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
mqttContext.retrieveFunction = publishRetrieveCallbackFailed;
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTPublishRetrieveFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
@@ -2511,6 +3280,8 @@ void test_MQTT_Connect_resendUnAckedPublishes4( void )
MQTTPubAckInfo_t outgoingRecords = { 0 };
/* MQTTPublishState_t expectedState = { 0 }; */
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
@@ -2520,17 +3291,18 @@ void test_MQTT_Connect_resendUnAckedPublishes4( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.retrieveFunction = publishRetrieveCallbackSuccess;
@@ -2546,12 +3318,13 @@ void test_MQTT_Connect_resendUnAckedPublishes4( void )
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
@@ -2571,6 +3344,8 @@ void test_MQTT_Connect_resendUnAckedPublishes5( void )
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
@@ -2580,17 +3355,18 @@ void test_MQTT_Connect_resendUnAckedPublishes5( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.transportInterface.send = transportSendSuccess;
@@ -2602,19 +3378,21 @@ void test_MQTT_Connect_resendUnAckedPublishes5( void )
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Query for any remaining packets pending to ack. */
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
}
+
void test_MQTT_Connect_resendUnAckedPublishes6( void )
{
MQTTContext_t mqttContext = { 0 };
@@ -2630,23 +3408,27 @@ void test_MQTT_Connect_resendUnAckedPublishes6( void )
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccessThenFail,
publishClearCallback );
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
@@ -2659,23 +3441,20 @@ void test_MQTT_Connect_resendUnAckedPublishes6( void )
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
/* First packet. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
/* Second packet. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier + 1 );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTPublishRetrieveFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
}
-/**
- * @brief Test success case for MQTT_Connect().
- */
-
#define MQTT_STATE_ARRAY_MAX_COUNT 1
void test_MQTT_Connect_happy_path1()
@@ -2687,11 +3466,13 @@ void test_MQTT_Connect_happy_path1()
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
+ uint32_t receiveMax = 128;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
@@ -2701,17 +3482,49 @@ void test_MQTT_Connect_happy_path1()
sessionPresent = false;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ MQTT_DeserializeConnAck_IgnoreAndReturn( MQTTSuccess );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_FALSE( mqttContext.waitingForPingResp );
+
+ /*Test MQTT_Connect with NULL buffer of propBuilder.*/
+ mqttContext.connectStatus = MQTTNotConnected;
+ MQTTPropBuilder_t propBuilder;
+ propBuilder.pBuffer = NULL;
+ MQTTPublishInfo_t willInfo = { 0 };
+ willInfo.pTopicName = "willTopic";
+ willInfo.topicNameLength = 10;
+ MQTT_ValidateWillProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ValidateConnectProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ValidateConnectProperties_ReturnThruPtr_pPacketSizeMaxValue( &receiveMax );
+ MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_IgnoreAndReturn( MQTTSuccess );
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, 0U, &sessionPresent, &propBuilder, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ mqttContext.connectStatus = MQTTNotConnected;
+ uint8_t buf[ 10 ];
+ incomingPacket.pRemainingData = buf;
+ incomingPacket.remainingLength = 2;
+ buf[ 1 ] = MQTT_REASON_CONNACK_IMPLEMENTATION_SPECIFIC_ERROR;
+ MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTServerRefused );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTServerRefused, status );
}
/**
@@ -2732,19 +3545,21 @@ void test_MQTT_Connect_happy_path2()
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Success. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ MQTT_DeserializeConnAck_IgnoreAndReturn( MQTTSuccess );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2771,6 +3586,7 @@ void test_MQTT_Connect_happy_path3()
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0x0, sizeof( MQTTPublishInfo_t ) );
memset( &connectInfo, 0x0, sizeof( MQTTConnectInfo_t ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* With non-NULL Will. */
@@ -2782,14 +3598,15 @@ void test_MQTT_Connect_happy_path3()
willInfo.pPayload = "Payload";
willInfo.payloadLength = 7;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
@@ -2812,15 +3629,19 @@ void test_MQTT_Connect_happy_path4()
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ 10 ] = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, 10,
- incomingRecords, 10 );
+ incomingRecords, 10, ackPropsBuf, ackPropsBufLength );
/* Request to establish a clean session. */
mqttContext.connectStatus = MQTTNotConnected;
@@ -2840,14 +3661,15 @@ void test_MQTT_Connect_happy_path4()
/* Set ping response flag to true to ensure it will be cleared. */
mqttContext.waitingForPingResp = true;
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
@@ -2881,6 +3703,7 @@ void test_MQTT_Connect_happy_path5()
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Request to establish a session if present and session present is received
@@ -2893,16 +3716,17 @@ void test_MQTT_Connect_happy_path5()
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
- MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
@@ -2928,6 +3752,7 @@ void test_MQTT_Connect_happy_path6()
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* CONNACK receive with timeoutMs=0. Retry logic will be used.
@@ -2938,14 +3763,16 @@ void test_MQTT_Connect_happy_path6()
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
- MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_IgnoreAndReturn( MQTTSuccess );
- status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
@@ -2962,9 +3789,12 @@ void test_MQTT_Publish( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
+ MQTTConnectionProperties_t properties = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
const uint16_t PACKET_ID = 1;
@@ -2974,10 +3804,65 @@ void test_MQTT_Publish( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ memset( &properties, 0x0, sizeof( properties ) );
+
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &mqttContext,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
- /* Verify parameters. */
- status = MQTT_Publish( NULL, &publishInfo, PACKET_ID );
+ mqttContext.connectStatus = MQTTConnected;
+
+ MQTTPropBuilder_t propBuilder = { 0 };
+ uint8_t buf[ 500 ];
+ size_t bufLength = sizeof( buf );
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+ propBuilder.currentIndex = 2;
+
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+
+ publishInfo.qos = 0;
+ publishInfo.pTopicName = "ab";
+ publishInfo.topicNameLength = 2;
+ publishInfo.retain = 1;
+ publishInfo.dup = 1;
+ publishInfo.pPayload = "Payload";
+ publishInfo.payloadLength = 7;
+
+ MQTT_ValidatePublishProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ propBuilder.pBuffer = NULL;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ propBuilder.pBuffer = buf;
+
+ MQTT_ValidatePublishProperties_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, &propBuilder );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3000,9 +3885,10 @@ void test_MQTT_Publish2( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- status = MQTT_Publish( &mqttContext, NULL, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, NULL, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3023,10 +3909,11 @@ void test_MQTT_Publish3( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
publishInfo.qos = MQTTQoS1;
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3049,11 +3936,12 @@ void test_MQTT_Publish4( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
publishInfo.payloadLength = 1;
publishInfo.pPayload = NULL;
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3070,16 +3958,18 @@ void test_MQTT_Publish5( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- transport.send = transportSendFailure;
+ /* transport.send = transportSendFailure; */
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Bad Parameter when getting packet size. */
publishInfo.qos = MQTTQoS0;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3100,12 +3990,14 @@ void test_MQTT_Publish6( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTNoMemory );
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
}
@@ -3122,6 +4014,8 @@ void test_MQTT_Publish_Storing_Publish_Success( void )
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
MQTTPublishState_t expectedState = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -3129,11 +4023,12 @@ void test_MQTT_Publish_Storing_Publish_Success( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
@@ -3144,10 +4039,10 @@ void test_MQTT_Publish_Storing_Publish_Success( void )
publishInfo.qos = MQTTQoS1;
expectedState = MQTTPublishSend;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
-
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTSuccess );
@@ -3157,7 +4052,7 @@ void test_MQTT_Publish_Storing_Publish_Success( void )
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
mqttContext.transportInterface.send = transportSendSuccess;
- status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 1, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3174,6 +4069,8 @@ void test_MQTT_Publish_Storing_Publish_Success_For_Duplicate_Publish( void )
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
MQTTPublishState_t expectedState = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -3181,11 +4078,12 @@ void test_MQTT_Publish_Storing_Publish_Success_For_Duplicate_Publish( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
@@ -3197,17 +4095,17 @@ void test_MQTT_Publish_Storing_Publish_Success_For_Duplicate_Publish( void )
publishInfo.dup = true;
expectedState = MQTTPublishSend;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
-
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
mqttContext.transportInterface.send = transportSendSuccess;
- status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 1, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3223,6 +4121,8 @@ void test_MQTT_Publish_Storing_Publish_Failed( void )
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -3230,11 +4130,12 @@ void test_MQTT_Publish_Storing_Publish_Failed( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackFailed,
publishRetrieveCallbackSuccess,
@@ -3243,16 +4144,16 @@ void test_MQTT_Publish_Storing_Publish_Failed( void )
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
-
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.transportInterface.send = transportSendSuccess;
- status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 1, NULL );
TEST_ASSERT_EQUAL_INT( MQTTPublishStoreFailed, status );
}
@@ -3268,6 +4169,8 @@ void test_MQTT_Publish_Storing_Publish_Failed_Due_To_Dup_Flag_Not_Set( void )
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -3275,11 +4178,13 @@ void test_MQTT_Publish_Storing_Publish_Failed_Due_To_Dup_Flag_Not_Set( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackFailed,
publishRetrieveCallbackSuccess,
@@ -3288,19 +4193,20 @@ void test_MQTT_Publish_Storing_Publish_Failed_Due_To_Dup_Flag_Not_Set( void )
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
-
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTBadParameter );
mqttContext.transportInterface.send = transportSendSuccess;
- status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 1, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
+
/**
* @brief Test that MQTT_Publish works as intended.
*/
@@ -3319,11 +4225,15 @@ void test_MQTT_Publish_DuplicatePublish( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
@@ -3338,11 +4248,51 @@ void test_MQTT_Publish_DuplicatePublish( void )
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
- status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
+void test_MQTT_Publish_DuplicatePublish2( void )
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTPublishInfo_t publishInfo = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTStatus_t status;
+ MQTTPubAckInfo_t outgoingPublishRecord[ 10 ];
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ transport.send = transportSendFailure;
+
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+
+ /* Always return success from now on. */
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
+
+ mqttContext.outgoingPublishRecordMaxCount = 10;
+ mqttContext.outgoingPublishRecords = outgoingPublishRecord;
+ mqttContext.connectStatus = MQTTConnected;
+
+ publishInfo.qos = MQTTQoS1;
+ publishInfo.dup = false;
+ publishInfo.pPayload = "TestPublish";
+ publishInfo.payloadLength = strlen( publishInfo.pPayload );
+ publishInfo.pTopicName = "TestTopic";
+ publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
+
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
+
+ TEST_ASSERT_EQUAL_INT( MQTTStateCollision, status );
+}
+
/**
* @brief Test that MQTT_Publish works as intended when the connection status is anything but MQTTConnected.
*/
@@ -3360,20 +4310,23 @@ void test_MQTT_Publish_not_connected( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test 1 connection status is MQTTNotConnected */
mqttContext.connectStatus = MQTTNotConnected;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
TEST_ASSERT_EQUAL_INT( MQTTStatusNotConnected, status );
/* Test 2 connection status is MQTTDisconnectPending */
mqttContext.connectStatus = MQTTDisconnectPending;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
TEST_ASSERT_EQUAL_INT( MQTTStatusDisconnectPending, status );
}
@@ -3395,17 +4348,20 @@ void test_MQTT_Publish_DuplicatePublish_UpdateFailed( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ mqttContext.connectStatus = MQTTConnected;
/* Always return success from now on. */
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSendFailed );
mqttContext.outgoingPublishRecordMaxCount = 10;
mqttContext.outgoingPublishRecords = outgoingPublishRecord;
- mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
publishInfo.dup = true;
@@ -3414,7 +4370,7 @@ void test_MQTT_Publish_DuplicatePublish_UpdateFailed( void )
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
- status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -3438,15 +4394,19 @@ void test_MQTT_Publish_WriteVSendsPartialBytes( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ReturnThruPtr_headerSize( &headerLen );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
mqttContext.outgoingPublishRecordMaxCount = 10;
mqttContext.outgoingPublishRecords = outgoingPublishRecord;
mqttContext.connectStatus = MQTTConnected;
@@ -3458,14 +4418,11 @@ void test_MQTT_Publish_WriteVSendsPartialBytes( void )
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
- status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 10, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief Test that MQTT_Publish works as intended.
- */
void test_MQTT_Publish7( void )
{
MQTTContext_t mqttContext = { 0 };
@@ -3481,10 +4438,13 @@ void test_MQTT_Publish7( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
mqttContext.connectStatus = MQTTConnected;
/* We need sendPacket to be called with at least 1 byte to send, so that
@@ -3492,7 +4452,7 @@ void test_MQTT_Publish7( void )
* publish header. */
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -3513,19 +4473,22 @@ void test_MQTT_Publish8( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- mqttContext.connectStatus = MQTTConnected;
-
/* We want to test the first call to sendPacket within sendPublish succeeding,
* and the second one failing. */
mqttContext.transportInterface.send = transportSendSucceedThenFail;
+
+ mqttContext.connectStatus = MQTTConnected;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -3546,15 +4509,17 @@ void test_MQTT_Publish9( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
mqttContext.transportInterface.send = transportSendSuccess;
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3575,6 +4540,8 @@ void test_MQTT_Publish10( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
@@ -3582,10 +4549,12 @@ void test_MQTT_Publish10( void )
/* Test that sending a publish without a payload succeeds. */
publishInfo.pPayload = NULL;
publishInfo.payloadLength = 0;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3607,6 +4576,7 @@ void test_MQTT_Publish11( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
@@ -3617,7 +4587,7 @@ void test_MQTT_Publish11( void )
/* Now for non zero QoS, which uses state engine. */
publishInfo.qos = MQTTQoS2;
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
@@ -3633,7 +4603,8 @@ void test_MQTT_Publish12( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPublishState_t expectedState = { 0 };
-
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
@@ -3645,13 +4616,15 @@ void test_MQTT_Publish12( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback2, &networkBuffer );
publishInfo.qos = MQTTQoS1;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
mqttContext.outgoingPublishRecords[ 0 ].packetId = 1;
mqttContext.outgoingPublishRecords[ 0 ].qos = MQTTQoS2;
@@ -3663,57 +4636,19 @@ void test_MQTT_Publish12( void )
mqttContext.connectStatus = MQTTConnected;
expectedState = MQTTPublishSend;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief Test that MQTT_Publish works as intended.
- */
-void test_MQTT_Publish13( void )
-{
- MQTTContext_t mqttContext = { 0 };
- MQTTPublishInfo_t publishInfo = { 0 };
- TransportInterface_t transport = { 0 };
- MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTStatus_t status;
- MQTTPubAckInfo_t incomingRecords = { 0 };
- MQTTPubAckInfo_t outgoingRecords = { 0 };
-
- const uint16_t PACKET_ID = 1;
-
- setupTransportInterface( &transport );
- setupNetworkBuffer( &networkBuffer );
- transport.send = transportSendFailure;
-
- memset( &mqttContext, 0x0, sizeof( mqttContext ) );
- memset( &publishInfo, 0x0, sizeof( publishInfo ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
-
- mqttContext.connectStatus = MQTTConnected;
-
- MQTT_InitStatefulQoS( &mqttContext,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
-
- publishInfo.qos = MQTTQoS1;
-
- MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Duplicate publish. dup flag is not marked by application. */
- MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
- TEST_ASSERT_EQUAL_INT( MQTTStateCollision, status );
-}
-
/**
* @brief Test that MQTT_Publish works as intended.
*/
@@ -3733,17 +4668,19 @@ void test_MQTT_Publish14( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Duplicate publish. dup flag is marked by application. */
publishInfo.dup = true;
-
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3765,6 +4702,7 @@ void test_MQTT_Publish15( void )
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
@@ -3772,10 +4710,12 @@ void test_MQTT_Publish15( void )
/* Duplicate publish. dup flag is marked by application.
* State record is not present. */
publishInfo.dup = true;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
+ status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
@@ -3802,6 +4742,7 @@ void test_MQTT_Publish_Send_Timeout( void )
transport.send = transportSendNoBytes;
/* Initialize the MQTT context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
@@ -3812,12 +4753,14 @@ void test_MQTT_Publish_Send_Timeout( void )
memset( &publishInfo, 0, sizeof( MQTTPublishInfo_t ) );
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
+ MQTT_ValidatePublishParams_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPublishPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Call the API function under test and expect that it detects a timeout in sending
* MQTT packet over the network. */
- status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
+ status = MQTT_Publish( &mqttContext, &publishInfo, 0, NULL );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
@@ -3832,50 +4775,86 @@ void test_MQTT_Disconnect_already_disconnected( void )
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t disconnectSize = 2;
+ uint32_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTNotConnected;
/* Send failure with network error. */
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
- MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Disconnect( &mqttContext );
+ MQTTSuccessFailReasonCode_t reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_Disconnect( &mqttContext, NULL, &reasonCode );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, status );
}
-/**
- * @brief Test that MQTT_Disconnect works as intended.
- */
-void test_MQTT_Disconnect1( void )
+void test_MQTTV5_Disconnect()
{
- MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
- uint8_t buffer[ 10 ];
- uint8_t * bufPtr = buffer;
- NetworkContext_t networkContext = { 0 };
+ MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSuccessFailReasonCode_t reasonCode = 0x00;
+ MQTTPropBuilder_t propBuilder = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- networkContext.buffer = &bufPtr;
- transport.pNetworkContext = &networkContext;
- transport.recv = transportRecvSuccess;
- transport.send = transportSendFailure;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- memset( &mqttContext, 0x0, sizeof( mqttContext ) );
- MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
- mqttContext.connectStatus = MQTTConnected;
+ context.connectStatus = MQTTConnected;
+ /* Invalid parameters. */
+ status = MQTT_Disconnect( NULL, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Verify parameters. */
- status = MQTT_Disconnect( NULL );
+ /* Reason code must be provided when properties are provided. */
+ status = MQTT_Disconnect( &context, &propBuilder, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_Disconnect( &context, NULL, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ uint8_t buf[ 10 ];
+ propBuilder.pBuffer = buf;
+
+ MQTT_ValidateDisconnectProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ status = MQTT_Disconnect( &context, &propBuilder, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+
+ /*Test MQTT_Disconnect with NULL property buffer.*/
+ context.connectStatus = MQTTConnected;
+ propBuilder.pBuffer = NULL;
+ MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_Disconnect( &context, &propBuilder, &reasonCode );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ propBuilder.pBuffer = buf;
+
+ /*Send failed*/
+ context.connectStatus = MQTTConnected;
+ context.transportInterface.send = transportSendFailure;
+ context.transportInterface.writev = NULL;
+ MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ reasonCode = MQTT_REASON_DISCONNECT_NORMAL_DISCONNECTION;
+ status = MQTT_Disconnect( &context, NULL, &reasonCode );
+ TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
@@ -3890,24 +4869,27 @@ void test_MQTT_Disconnect2( void )
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t disconnectSize = 2;
+ uint32_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
+ transport.writev = NULL;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Send failure with network error. */
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
- MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Disconnect( &mqttContext );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Disconnect( &mqttContext, NULL, 0x00 );
TEST_ASSERT_EQUAL( MQTTSendFailed, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
}
@@ -3924,7 +4906,6 @@ void test_MQTT_Disconnect3( void )
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -3932,35 +4913,26 @@ void test_MQTT_Disconnect3( void )
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
+ transport.writev = NULL;
+ transport.send = transportSendNoBytes;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Send failure with timeout in calling transport send. */
- transport.send = transportSendNoBytes;
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
- MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTT_Disconnect( &mqttContext );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_Disconnect( &mqttContext, NULL, 0x00 );
TEST_ASSERT_EQUAL( MQTTSendFailed, status );
}
-MQTTStatus_t MQTT_SerializeDisconnect_stub( const MQTTFixedBuffer_t * pFixedBuffer,
- int numcalls )
-{
- ( void ) numcalls;
-
- pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
- pFixedBuffer->pBuffer[ 1 ] = 0;
-
- return MQTTSuccess;
-}
-
-/**
- * @brief Test that MQTT_Disconnect works as intended.
- */
-void test_MQTT_Disconnect4( void )
+/**
+ * @brief Test that MQTT_Disconnect works as intended.
+ */
+void test_MQTT_Disconnect4( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
@@ -3969,7 +4941,7 @@ void test_MQTT_Disconnect4( void )
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t disconnectSize = 2;
+ uint32_t disconnectSize = 2;
/* Fill the buffer with garbage data. */
memset( mqttBuffer, 0xAB, MQTT_TEST_BUFFER_LENGTH );
@@ -3983,19 +4955,27 @@ void test_MQTT_Disconnect4( void )
transport.writev = NULL;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Successful send. */
mqttContext.transportInterface.send = mockSend;
+ MQTT_ValidateDisconnectProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
- MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_SerializeDisconnect_Stub( MQTT_SerializeDisconnect_stub );
- /* Write a disconnect packet into the buffer. */
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb ); /* Write a disconnect packet into the buffer. */
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
- status = MQTT_Disconnect( &mqttContext );
+ MQTTPropBuilder_t propBuffer = { 0 };
+ uint8_t buf[ 10 ];
+ propBuffer.pBuffer = buf;
+ propBuffer.bufferLength = sizeof( buf );
+ propBuffer.currentIndex = 5;
+ MQTTSuccessFailReasonCode_t reasonCode = 0x00;
+
+ status = MQTT_Disconnect( &mqttContext, &propBuffer, &reasonCode );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
@@ -4015,7 +4995,7 @@ void test_MQTT_Disconnect4_status_disconnect_pending( void )
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t disconnectSize = 2;
+ uint32_t disconnectSize = 2;
/* Fill the buffer with garbage data. */
memset( mqttBuffer, 0xAB, MQTT_TEST_BUFFER_LENGTH );
@@ -4029,6 +5009,7 @@ void test_MQTT_Disconnect4_status_disconnect_pending( void )
transport.writev = NULL;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTDisconnectPending;
@@ -4036,19 +5017,18 @@ void test_MQTT_Disconnect4_status_disconnect_pending( void )
mqttContext.transportInterface.send = mockSend;
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
- MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_SerializeDisconnect_Stub( MQTT_SerializeDisconnect_stub );
+ serializeDisconnectFixed_Stub( MQTTV5_SerializeDisconnectFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Write a disconnect packet into the buffer. */
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
- status = MQTT_Disconnect( &mqttContext );
+ status = MQTT_Disconnect( &mqttContext, NULL, 0 );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
/* At disconnect, the buffer is cleared of any pending packets. */
TEST_ASSERT_EACH_EQUAL_UINT8( 0, mqttBuffer, MQTT_TEST_BUFFER_LENGTH );
}
-/* ========================================================================== */
/**
* @brief Test that MQTT_GetPacketId works as intended.
@@ -4063,6 +5043,7 @@ void test_MQTT_GetPacketId( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Verify parameters. */
@@ -4094,6 +5075,7 @@ void test_MQTT_ProcessLoop_Invalid_Params( void )
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
setupTransportInterface( &transport );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -4123,6 +5105,7 @@ void test_MQTT_ProcessLoop_discardPacket( void )
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -4137,7 +5120,7 @@ void test_MQTT_ProcessLoop_discardPacket( void )
mqttStatus = MQTT_ProcessLoop( &context );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
void test_MQTT_ProcessLoop_IncomingBufferNotInit( void )
@@ -4152,6 +5135,7 @@ void test_MQTT_ProcessLoop_IncomingBufferNotInit( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* First byte shows that it is a publish type packet. */
@@ -4191,6 +5175,7 @@ void test_MQTT_ProcessLoop_IncomingBufferNotInitQoS0( void )
isEventCallbackInvoked = false;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* First byte shows that it is a publish type packet. */
@@ -4230,6 +5215,7 @@ void test_MQTT_ProcessLoop_HandleKeepAlive( void )
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* Set this value such that the library will be forced to send keep alive. */
@@ -4247,16 +5233,14 @@ void test_MQTT_ProcessLoop_HandleKeepAlive1( void )
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
- size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+ uint32_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
-
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
-
context.connectStatus = MQTTConnected;
-
/* Verify MQTTSuccess is returned. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
@@ -4283,6 +5267,7 @@ void test_MQTT_ProcessLoop_HandleKeepAlive2( void )
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* Set this value such that the library will be forced to send keep alive. */
@@ -4308,8 +5293,8 @@ void test_MQTT_ProcessLoop_RecvFailed( void )
transport.recv = transportRecvFailure;
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- context.connectStatus = MQTTConnected;
mqttStatus = MQTT_ProcessLoop( &context );
@@ -4327,6 +5312,7 @@ void test_MQTT_ProcessLoop_RecvFailed_disconnected( void )
transport.recv = transportRecvFailure;
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
mqttStatus = MQTT_ProcessLoop( &context );
@@ -4345,6 +5331,7 @@ void test_MQTT_ReceiveLoop_KeepAliveACK( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -4376,11 +5363,10 @@ void test_MQTT_ProcessLoop_discardPacket_second_recv_fail( void )
transport.recv = transportRecvOneSuccessOneFail;
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
context.connectStatus = MQTTConnected;
-
context.networkBuffer.size = 20;
incomingPacket.type = currentPacketType;
@@ -4408,16 +5394,25 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path1( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingCallback[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingCallback, 10 );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingCallback, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
@@ -4431,6 +5426,8 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path1( void )
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectParams.incomingPublish = true;
+ publishInfo.qos = MQTTQoS1;
+ expectParams.pPubInfo = &publishInfo;
expectProcessLoopCalls( &context, &expectParams );
}
@@ -4447,16 +5444,25 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path2( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ MQTTPublishInfo_t publishInfo = { 0 };
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
@@ -4470,6 +5476,8 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path2( void )
expectParams.stateAfterDeserialize = MQTTPubRecSend;
expectParams.stateAfterSerialize = MQTTPubRelPending;
expectParams.incomingPublish = true;
+ publishInfo.qos = MQTTQoS1;
+ expectParams.pPubInfo = &publishInfo;
expectProcessLoopCalls( &context, &expectParams );
}
@@ -4488,10 +5496,13 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path3( void )
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context,
&transport,
getTime,
@@ -4499,9 +5510,14 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path3( void )
&networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
context.connectStatus = MQTTConnected;
@@ -4541,15 +5557,23 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path4( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
context.connectStatus = MQTTConnected;
@@ -4567,6 +5591,8 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path4( void )
expectParams.stateAfterSerialize = MQTTPubRelPending;
expectParams.incomingPublish = true;
expectParams.updateStateStatus = MQTTStateCollision;
+ publishInfo.qos = MQTTQoS1;
+ expectParams.pPubInfo = &publishInfo;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
}
@@ -4584,15 +5610,23 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path5( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
context.connectStatus = MQTTConnected;
@@ -4606,6 +5640,8 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path5( void )
expectParams.updateStateStatus = MQTTStateCollision;
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
+ publishInfo.qos = MQTTQoS1;
+ expectParams.pPubInfo = &publishInfo;
/* No loop statuses have changed from before. */
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
@@ -4624,14 +5660,23 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path6( void )
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10, ackPropsBuf, ackPropsBufLength );
+ MQTTPropBuilder_t ackPropsBuffer;
+ ackPropsBuffer.pBuffer = ackPropsBuf;
+ ackPropsBuffer.bufferLength = ackPropsBufLength;
+ context.ackPropsBuffer = ackPropsBuffer;
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
@@ -4650,6 +5695,8 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path6( void )
expectParams.updateStateStatus = MQTTSuccess;
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
+ publishInfo.qos = MQTTQoS1;
+ expectParams.pPubInfo = &publishInfo;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_TRUE( isEventCallbackInvoked );
}
@@ -4669,16 +5716,23 @@ void test_MQTT_ProcessLoop_handleIncomingPublish_Error_Paths( void )
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
modifyIncomingPacketStatus = MQTTSuccess;
@@ -4736,6 +5790,7 @@ void test_MQTT_ProcessLoop_Zero_Duration_And_Partial_Network_Read( void )
transport.recv = transportRecvOneByte;
/* Initialize the context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -4777,7 +5832,8 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
@@ -4828,6 +5884,26 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths( void )
expectParams.stateAfterDeserialize = MQTTPublishDone;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
+}
+
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths5( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ context.connectStatus = MQTTConnected;
+
+ modifyIncomingPacketStatus = MQTTSuccess;
/* Mock the receiving of a PINGRESP packet type and expect the appropriate
* calls made from the process loop. */
@@ -4850,6 +5926,7 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths( void )
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTServerRefused;
+ expectParams.processLoopStatus = MQTTServerRefused;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_TRUE( isEventCallbackInvoked );
@@ -4873,13 +5950,24 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Clear_Publish_Copies( void )
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
mqttStatus = MQTT_InitRetransmits( &context, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
@@ -4927,11 +6015,13 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Clear_Publish_Copies( void )
expectProcessLoopCalls( &context, &expectParams );
}
+
/**
* @brief This test case covers all calls to the private method,
* handleIncomingAck(...),
* that result in the process loop returning an error.
*/
+
void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths( void )
{
MQTTStatus_t mqttStatus;
@@ -4943,6 +6033,7 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths( void )
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -4972,6 +6063,131 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths( void )
/* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
* here PUBREC but thr connection status is MQTTNotConnected. */
+ context.connectStatus = MQTTNotConnected;
+ currentPacketType = MQTT_PACKET_TYPE_PUBREC;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ expectParams.stateAfterSerialize = MQTTPubCompPending;
+ expectParams.serializeStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTStatusNotConnected;
+ context.connectStatus = MQTTNotConnected;
+ expectProcessLoopCalls( &context, &expectParams );
+ context.connectStatus = MQTTConnected;
+
+ /* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
+ * here PUBREC but thr connection status is MQTTNotConnected. */
+ currentPacketType = MQTT_PACKET_TYPE_PUBREC;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ expectParams.stateAfterSerialize = MQTTPubCompPending;
+ expectParams.serializeStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTStatusDisconnectPending;
+ context.connectStatus = MQTTDisconnectPending;
+ expectProcessLoopCalls( &context, &expectParams );
+ context.connectStatus = MQTTConnected;
+
+ /* Verify that MQTTBadResponse is propagated when deserialization fails upon
+ * receiving a PUBACK. */
+ currentPacketType = MQTT_PACKET_TYPE_PUBACK;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.deserializeStatus = MQTTBadResponse;
+ expectParams.stateAfterDeserialize = MQTTStateNull;
+ expectParams.processLoopStatus = MQTTBadResponse;
+ /* The other loop parameter fields are irrelevant. */
+ expectProcessLoopCalls( &context, &expectParams );
+
+ /* Verify that MQTTBadResponse is propagated when deserialization fails upon
+ * receiving a PINGRESP. */
+ currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.deserializeStatus = MQTTBadResponse;
+ expectParams.stateAfterDeserialize = MQTTStateNull;
+ expectParams.processLoopStatus = MQTTBadResponse;
+ /* The other loop parameter fields are irrelevant. */
+ expectProcessLoopCalls( &context, &expectParams );
+
+ /* Verify that MQTTBadResponse is propagated when deserialization fails upon
+ * receiving a SUBACK. */
+ currentPacketType = MQTT_PACKET_TYPE_SUBACK;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.deserializeStatus = MQTTBadResponse;
+ expectParams.processLoopStatus = MQTTBadResponse;
+ /* The other loop parameter fields are irrelevant. */
+ expectProcessLoopCalls( &context, &expectParams );
+
+ /* Verify that MQTTIllegalState is returned if MQTT_UpdateStateAck(...)
+ * provides an unknown state such as MQTTStateNull to sendPublishAcks(...). */
+ currentPacketType = MQTT_PACKET_TYPE_PUBREC;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ expectParams.stateAfterSerialize = MQTTStateNull;
+ expectParams.processLoopStatus = MQTTIllegalState;
+ expectProcessLoopCalls( &context, &expectParams );
+}
+
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_PathsWithProperties( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ context.connectStatus = MQTTConnected;
+
+ modifyIncomingPacketStatus = MQTTSuccess;
+
+ /* Verify that MQTTBadResponse is propagated when deserialization fails upon
+ * receiving an unknown packet type. */
+ currentPacketType = MQTT_PACKET_TYPE_INVALID;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.deserializeStatus = MQTTBadResponse;
+ expectParams.processLoopStatus = MQTTBadResponse;
+ expectProcessLoopCalls( &context, &expectParams );
+
+ /* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
+ * here PUBREC but thr connection status is MQTTNotConnected. */
+
+ /* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
+ * here PUBREC but thr connection status is MQTTNotConnected. */
+ context.connectStatus = MQTTNotConnected;
+ currentPacketType = MQTT_PACKET_TYPE_PUBREC;
+ /* Set expected return values in the loop. */
+ resetProcessLoopParams( &expectParams );
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ expectParams.stateAfterSerialize = MQTTPubCompPending;
+ expectParams.serializeStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTStatusNotConnected;
+ context.connectStatus = MQTTNotConnected;
+ expectProcessLoopCalls( &context, &expectParams );
+
+
+ context.connectStatus = MQTTNotConnected;
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
@@ -5039,6 +6255,62 @@ void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths( void )
expectProcessLoopCalls( &context, &expectParams );
}
+void test_MQTT_ProcessLoop_handleIncomingAck_InvalidReasonCode( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
+
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallbackInvalidRC, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+
+ context.connectStatus = MQTTConnected;
+
+ context.waitingForPingResp = false;
+ context.keepAliveIntervalSec = 0;
+ expectParams.incomingPublish = false;
+ expectParams.updateStateStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTSuccess;
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+
+
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
+
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
@@ -5060,6 +6332,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths1( void )
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5074,7 +6347,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths1( void )
/* Set expected return values in the loop. All success. */
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
- incomingPacket.type = currentPacketType;
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
@@ -5116,11 +6389,13 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths2( void )
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Coverage for the branch path where keep alive interval is greater than 0,
* and the interval has not expired. PINGREQ should not be sent. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.keepAliveIntervalSec = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
@@ -5129,7 +6404,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths2( void )
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
- incomingPacket.type = currentPacketType;
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBACK;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
@@ -5165,6 +6440,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths3( void )
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5178,7 +6454,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths3( void )
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
- incomingPacket.type = currentPacketType;
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
@@ -5214,6 +6490,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths4( void )
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5224,7 +6501,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths4( void )
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
- incomingPacket.type = currentPacketType;
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
@@ -5262,6 +6539,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths1( void )
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5299,6 +6577,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths2( void )
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5347,6 +6626,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths3( void )
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5360,7 +6640,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths3( void )
context.waitingForPingResp = false;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
- size_t packetSize = MQTT_PACKET_PINGREQ_SIZE;
+ uint32_t packetSize = MQTT_PACKET_PINGREQ_SIZE;
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
@@ -5381,6 +6661,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths4( void )
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
+ uint32_t packetSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
@@ -5391,6 +6672,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths4( void )
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5419,7 +6701,6 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths4( void )
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNeedMoreBytes );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
- size_t packetSize = MQTT_PACKET_PINGREQ_SIZE;
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
@@ -5450,6 +6731,7 @@ void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths5( void )
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5497,6 +6779,7 @@ void test_MQTT_ProcessLoop_Receive_Failed( void )
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
@@ -5526,6 +6809,11 @@ void test_MQTT_ProcessLoop_Timer_Overflow( void )
MQTTPublishState_t publishState = MQTTPubAckSend;
MQTTPublishState_t ackState = MQTTPublishDone;
MQTTPubAckInfo_t incomingPublishRecords[ 10 ];
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
+
+ publishInfo.qos = MQTTQoS1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
@@ -5535,10 +6823,16 @@ void test_MQTT_ProcessLoop_Timer_Overflow( void )
globalEntryTime = UINT32_MAX - MQTT_OVERFLOW_OFFSET;
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, incomingPublishRecords, 10 );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, incomingPublishRecords, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
@@ -5547,6 +6841,18 @@ void test_MQTT_ProcessLoop_Timer_Overflow( void )
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Assume QoS = 1 so that a PUBACK will be sent after receiving PUBLISH. */
MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &publishState );
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &ackState );
+
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ /* Assume QoS = 1 so that a PUBACK will be sent after receiving PUBLISH. */
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &publishState );
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
@@ -5572,15 +6878,29 @@ void test_MQTT_ReceiveLoop( void )
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
-
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Verify that a NULL Context returns an error. */
- mqttStatus = MQTT_ReceiveLoop( NULL );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ /* Verify that a NULL Context returns an error. */
+ mqttStatus = MQTT_ReceiveLoop( NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Verify that a NULL time function returns an error. */
context.getTime = NULL;
@@ -5626,572 +6946,864 @@ void test_MQTT_ReceiveLoop( void )
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
-/* ========================================================================== */
-
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTBadParameter
- * with an invalid parameter. This test case also gives us coverage over
- * the private method, validateSubscribeUnsubscribeParams(...).
- */
-void test_MQTT_Subscribe_invalid_params( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths1( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Call subscribe with a NULL context. */
- mqttStatus = MQTT_Subscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ /*Update state returns bad response.*/
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Call subscribe with a NULL subscription list. */
- mqttStatus = MQTT_Subscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
- /* Call subscribe with 0 subscriptions. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ context.connectStatus = MQTTConnected;
- /* Packet ID cannot be 0 per MQTT 3.1.1 spec. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 0 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Incoming publish records NULL but QoS > 0. */
- subscribeInfo.qos = MQTTQoS1;
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 10 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ stateAfterSerialize = MQTTPubCompPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
-static uint8_t * MQTT_SerializeSubscribedHeader_cb( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId,
- int numcallbacks )
-{
- ( void ) remainingLength;
- ( void ) pIndex;
- ( void ) packetId;
- ( void ) numcallbacks;
+ /*Packet size is greater than the allowed maximum packet size.*/
- return pIndex;
+ context.connectionProperties.serverMaxPacketSize = 1;
+ context.connectStatus = MQTTConnected;
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ stateAfterSerialize = MQTTPubCompPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-static uint8_t * MQTT_SerializeSubscribedHeader_cb1( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId,
- int numcallbacks )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths2( void )
{
- ( void ) remainingLength;
- ( void ) pIndex;
- ( void ) packetId;
- ( void ) numcallbacks;
+ MQTTStatus_t status;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+
+ /*Update state returns bad response.*/
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ context.connectStatus = MQTTConnected;
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- return pIndex + 5;
+ modifyIncomingPacketStatus = MQTTSuccess;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-static uint8_t * MQTT_SerializeSubscribedHeader_cb2( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId,
- int numcallbacks )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths3( void )
{
- ( void ) remainingLength;
- ( void ) pIndex;
- ( void ) packetId;
- ( void ) numcallbacks;
-
- memcpy( pIndex, SubscribeHeader, SubscribeHeaderLength );
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ uint16_t packetId = 2;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
- return pIndex + SubscribeHeaderLength;
-}
+ /*Invalid packet parameters.*/
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
-static uint8_t * MQTT_SerializeUnsubscribedHeader_cb2( size_t remainingLength,
- uint8_t * pIndex,
- uint16_t packetId,
- int numcallbacks )
-{
- ( void ) remainingLength;
- ( void ) pIndex;
- ( void ) packetId;
- ( void ) numcallbacks;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- memcpy( pIndex, UnsubscribeHeader, UnsubscribeHeaderLength );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
- return pIndex + UnsubscribeHeaderLength;
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ context.connectStatus = MQTTConnected;
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
- */
-void test_MQTT_Subscribe_happy_path( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths4( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 2;
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ /*Invalid packet parameters.*/
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
- mqttStatus = MQTT_InitStatefulQoS( &context,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
-
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
-
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe does not return success if the connect status
- * is anythin but MQTTConnected.
- */
-void test_MQTT_Subscribe_happy_path_not_connected( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths_disconnect( void )
{
- MQTTStatus_t mqttStatus;
- MQTTContext_t context = { 0 };
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
+ publishInfo.qos = MQTTQoS1;
+
+ memset( &globalMQTTContext, 0, sizeof( globalMQTTContext ) );
+
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
+ transport.send = transportSendFailure;
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &globalMQTTContext, &transport, getTime, eventCallbackNopropsNoReason, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ globalMQTTContext.connectStatus = MQTTConnected;
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ globalMQTTContext.ackPropsBuffer = ackPropsBuffer;
- mqttStatus = MQTT_InitStatefulQoS( &context,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ globalMQTTContext.connectionProperties.serverMaxPacketSize = MQTT_MAX_PACKET_SIZE;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &globalMQTTContext,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRecSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &stateAfterDeserialize );
- /* Test 1 connect status is MQTTNotConnected */
- context.connectStatus = MQTTNotConnected;
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
+ MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Test 2 connect status is MQTTDisconnectPending*/
- context.connectStatus = MQTTDisconnectPending;
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
+ status = MQTT_ProcessLoop( &globalMQTTContext );
+ TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
- */
-void test_MQTT_Subscribe_happy_path1( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths2( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 2 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo[ 0 ] );
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
- mqttStatus = MQTT_InitStatefulQoS( &context,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ stateAfterSerialize = MQTTPubCompPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
- */
-void test_MQTT_Subscribe_happy_path2( void )
+void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Paths3( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 2 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
+
+ publishInfo.qos = MQTTQoS1;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo[ 0 ] );
- setupSubscriptionInfo( &subscribeInfo[ 1 ] );
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
- mqttStatus = MQTT_InitStatefulQoS( &context,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback3, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb1 );
-
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 2, MQTT_FIRST_VALID_PACKET_ID );
-
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRecSend;
+ stateAfterSerialize = MQTTPubRelPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-void test_MQTT_Subscribe_MultipleSubscriptions( void )
+void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Paths4( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 5 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
- TEST_ASSERT_EQUAL_MESSAGE( 6U, MQTT_SUB_UNSUB_MAX_VECTORS,
- "This test is configured to work with MQTT_SUB_UNSUB_MAX_VECTORS defined as 6." );
+ publishInfo.qos = MQTTQoS1;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
- transport.writev = transportWritevSubscribeSuccess;
-
setupNetworkBuffer( &networkBuffer );
-
- subscribeInfo[ 0 ].qos = MQTTQoS1;
- subscribeInfo[ 0 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
- subscribeInfo[ 0 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
-
- subscribeInfo[ 1 ].qos = MQTTQoS2;
- subscribeInfo[ 1 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER1;
- subscribeInfo[ 1 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH1;
-
- subscribeInfo[ 2 ].qos = MQTTQoS0;
- subscribeInfo[ 2 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER2;
- subscribeInfo[ 2 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH2;
-
- subscribeInfo[ 3 ].qos = MQTTQoS1;
- subscribeInfo[ 3 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER3;
- subscribeInfo[ 3 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH3;
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
- mqttStatus = MQTT_InitStatefulQoS( &context,
- &outgoingRecords, 4,
- &incomingRecords, 4 );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback3, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb2 );
-
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID );
-
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubAckSend;
+ stateAfterSerialize = MQTTPublishDone;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
- * if transport interface send returns an error.
- */
-void test_MQTT_Subscribe_error_paths1( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths3( void )
{
- MQTTStatus_t mqttStatus = { 0 };
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Verify that an error is propagated when transport interface returns an error. */
- setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
- transport.send = transportSendFailure;
- transport.writev = NULL;
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback4, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- /* Verify MQTTSendFailed is propagated when transport interface returns an error. */
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- /* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ stateAfterSerialize = MQTTPubCompPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
- * if transport interface send returns an error.
- */
-void test_MQTT_Subscribe_error_paths2( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_PathsInvalidRC( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Verify that an error is propagated when transport interface returns an error. */
- setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
- transport.writev = NULL;
- /* Case when there is timeout in sending data through transport send. */
- transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback3, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
- * if transport interface fails to send and the connection status is converted to
- * MQTTDisconnectPending
- */
-void test_MQTT_Subscribe_error_paths_with_transport_failure( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths_Send_Pubcomp( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Verify that an error is propagated when transport interface returns an error. */
- setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
- transport.writev = NULL;
- transport.send = transportSendFailure;
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREL;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback4, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
- TEST_ASSERT_EQUAL( MQTTDisconnectPending, context.connectStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubCompSend;
+ stateAfterSerialize = MQTTPublishDone;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
- * if transport interface send fails and timer overflows.
- */
-void test_MQTT_Subscribe_error_paths_timerOverflowCheck( void )
+void test_MQTT_ProcessLoop_handleIncomingPublish_Error_Paths_Send_Puback( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
-
- globalEntryTime = UINT32_MAX - 2U;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTTPublishInfo_t publishInfo = { 0 };
- /* The timer function can be called a maximum of these many times
- * (which is way less than UINT32_MAX). This ensures that if overflow
- * check is not correct, then the timer mock call will fail and assert. */
- getTimeMockCallLimit = MQTT_SEND_TIMEOUT_MS + 1;
+ publishInfo.qos = MQTTQoS1;
- /* Verify that an error is propagated when transport interface returns an error. */
- setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ /*Using event call back to set reason string and user properties,*/
setupTransportInterface( &transport );
- transport.writev = NULL;
- /* Case when there is timeout in sending data through transport send. */
- transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
-
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTimeMock, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback4, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
-
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
- TEST_ASSERT_EQUAL( -1, getTimeMockCallLimit );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubAckSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
- * if transport interface send fails and timer overflows.
- */
-void test_MQTT_Subscribe_error_paths_timerOverflowCheck1( void )
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths4( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTPublishState_t stateAfterSerialize;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint16_t packetId = 1;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- globalEntryTime = UINT32_MAX - MQTT_SEND_TIMEOUT_MS + 1;
+ /*Using event call back to set reason string and user properties,*/
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback4, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* The timer function can be called a exactly 2 times. First when setting
- * the initial time, next time when checking for timeout.
- */
- getTimeMockBigTimeStepCallLimit = 2;
+ context.connectStatus = MQTTConnected;
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ stateAfterSerialize = MQTTPubCompPending;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+}
- /* Verify that an error is propagated when transport interface returns an error. */
+void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths5( void )
+{
+ MQTTStatus_t status;
+ MQTTPublishState_t stateAfterDeserialize;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint16_t packetId = 1;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ /*Unable to send the packet using transport interface.*/
+ setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback2, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ context.connectStatus = MQTTConnected;
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ context.transportInterface.send = transportSendNoBytes;
+ context.transportInterface.writev = NULL;
+ modifyIncomingPacketStatus = MQTTSuccess;
+ stateAfterDeserialize = MQTTPubRelSend;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeAck_ReturnThruPtr_pPacketId( &packetId );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
+ MQTT_ValidatePublishAckProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetAckPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ serializeAckFixed_Stub( MQTTV5_SerializeAckFixed_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
+}
+
+void test_MQTT_ProcessLoop_handleIncomingDisconnect( void )
+{
+ MQTTStatus_t status;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTReasonCodeInfo_t disconnectInfo;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+
+ memset( &disconnectInfo, 0x0, sizeof( disconnectInfo ) );
setupTransportInterface( &transport );
- transport.writev = NULL;
- /* Case when there is timeout in sending data through transport send. */
- transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
+ setupNetworkBuffer( &networkBuffer );
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTimeMockBigTimeStep, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ incomingPacket.type = MQTT_PACKET_TYPE_DISCONNECT;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeDisconnect_IgnoreAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
context.connectStatus = MQTTConnected;
+ /* Invalid packet parameters. */
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ /* Return bad response. */
+ MQTT_DeserializeDisconnect_IgnoreAndReturn( MQTTBadResponse );
- MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
- mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
- TEST_ASSERT_EQUAL( -1, getTimeMockBigTimeStepCallLimit );
-}
+ /* In case of malformed packet, the library must ignore the packet and send a disconnect
+ * packet of it's own with a reason code of malformed packet. */
+ MQTT_GetDisconnectPacketSize_Stub( MQTT_GetDisconnectPacketSize_ExpectReasonMalformed );
+ serializeDisconnectFixed_Stub( serializeDisconnectFixed_cb_OneByte );
-/* ========================================================================== */
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
-/**
- * @brief This test case verifies that MQTT_Unsubscribe returns MQTTBadParameter
- * with an invalid parameter. This test case also gives us coverage over
- * the private method, validateSubscribeUnsubscribeParams(...).
- */
-void test_MQTT_Unsubscribe_invalid_params( void )
+ status = MQTT_ProcessLoop( &context );
+
+ /* On failure to process the disconnect packet, coreMQTT should send a
+ * Disconnect of it's own and disconnect. */
+ TEST_ASSERT_EQUAL_INT( MQTTStatusNotConnected, status );
+}
+
+void test_incoming_disconnect_failsSendingDisconnect( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t status;
MQTTContext_t context = { 0 };
- MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTReasonCodeInfo_t disconnectInfo;
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Call subscribe with a NULL context. */
- mqttStatus = MQTT_Unsubscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ memset( &disconnectInfo, 0x0, sizeof( disconnectInfo ) );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- /* Call subscribe with a NULL subscription list. */
- mqttStatus = MQTT_Unsubscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_DISCONNECT;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- /* Call subscribe with 0 subscriptions. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Packet ID cannot be 0 per MQTT 3.1.1 spec. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, 0 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+
+ context.connectStatus = MQTTConnected;
+
+ /* Invalid packet parameters. */
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ /* Return bad response. */
+ MQTT_DeserializeDisconnect_IgnoreAndReturn( MQTTBadResponse );
+
+ /* In case of malformed packet, the library must ignore the packet and send a disconnect
+ * packet of it's own with a reason code of malformed packet. */
+ MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTBadResponse );
+
+ status = MQTT_ProcessLoop( &context );
+
+ /* On failure to process the disconnect packet, coreMQTT should send a
+ * Disconnect of it's own and disconnect. */
+ TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
+}
+
+static void setupSubscriptionInfo( MQTTSubscribeInfo_t * pSubscribeInfo )
+{
+ pSubscribeInfo->qos = MQTTQoS1;
+ pSubscribeInfo->pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
+ pSubscribeInfo->topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
+ pSubscribeInfo->noLocalOption = 0;
+ pSubscribeInfo->retainAsPublishedOption = 0;
+ pSubscribeInfo->retainHandlingOption = retainSendOnSubIfNotPresent;
+}
+
+
+static uint8_t * MQTTV5_SerializeSubscribedHeader_cb( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId,
+ int numcallbacks )
+{
+ ( void ) remainingLength;
+ ( void ) pIndex;
+ ( void ) packetId;
+ ( void ) numcallbacks;
+
+ return pIndex;
}
-static uint8_t * MQTT_SerializeUnsubscribeHeader_cb( size_t remainingLength,
+static uint8_t * MQTT_SerializeSubscribedHeader_cb2( uint32_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
@@ -6201,186 +7813,448 @@ static uint8_t * MQTT_SerializeUnsubscribeHeader_cb( size_t remainingLength,
( void ) packetId;
( void ) numcallbacks;
- return pIndex;
+ memcpy( pIndex, SubscribeHeader, SubscribeHeaderLength );
+
+ return pIndex + SubscribeHeaderLength;
}
-/**
- * @brief This test case verifies that MQTT_Unsubscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
- */
-void test_MQTT_Unsubscribe_happy_path( void )
+static uint8_t * MQTT_SerializeUnsubscribedHeader_cb2( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId,
+ int numcallbacks )
+{
+ ( void ) remainingLength;
+ ( void ) pIndex;
+ ( void ) packetId;
+ ( void ) numcallbacks;
+
+ memcpy( pIndex, UnsubscribeHeader, UnsubscribeHeaderLength );
+
+ return pIndex + UnsubscribeHeaderLength;
+}
+
+
+void test_MQTTV5_Subscribe_invalid_params( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
- TransportInterface_t transport = { 0 };
- MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
- setupTransportInterface( &transport );
- setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo );
+ /* Call subscribe with a NULL context. */
+ mqttStatus = MQTT_Subscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+
+ /* Call with a NULL subscription list. */
+ mqttStatus = MQTT_Subscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Call subscribe with 0 subscriptions. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Packet ID cannot be 0 per MQTT 5.0 spec. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Incoming publish records NULL but QoS > 0. */
+ subscribeInfo.qos = MQTTQoS1;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
subscribeInfo.qos = MQTTQoS0;
- /* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ /* Test topic filter length is zero */
+ subscribeInfo.pTopicFilter = "test/topic";
+ subscribeInfo.topicFilterLength = 0;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test NULL topic filter */
+ subscribeInfo.pTopicFilter = NULL;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.topicFilterLength = 2;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.pTopicFilter = "abc/def";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+
+ /* Test invalid QoS level */
+ subscribeInfo.qos = 3; /* QoS must be 0, 1, or 2 */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test invalid shared subscription */
+ subscribeInfo.qos = 0;
+ subscribeInfo.pTopicFilter = "$share/invalid#";
+ subscribeInfo.noLocalOption = 0;
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.pTopicFilter = "$share/abc/#";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.pTopicFilter = "abc";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ subscribeInfo.retainHandlingOption = 3;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.retainHandlingOption = 1;
+ subscribeInfo.qos = 3;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.qos = 0;
+ subscribeInfo.retainHandlingOption = 0;
+ context.connectionProperties.isWildcardAvailable = 0U;
+ subscribeInfo.pTopicFilter = "$share/abc/#";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.qos = 0;
+ subscribeInfo.retainHandlingOption = 0;
+ context.connectionProperties.isWildcardAvailable = 1U;
+ subscribeInfo.pTopicFilter = "$share/abc/#";
+ context.connectionProperties.isSharedAvailable = 0U;
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.pTopicFilter = "$share/+/abc";
+ context.connectionProperties.isSharedAvailable = 1U;
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test shared subscription with '#' in share name */
+ subscribeInfo.pTopicFilter = "$share/group#name/topic";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ context.connectionProperties.isSharedAvailable = 1U;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test shared subscription with empty share name */
+ subscribeInfo.pTopicFilter = "$share//topic";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test shared subscription with no topic after share name */
+ subscribeInfo.pTopicFilter = "$share/group/";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test topic filter with wildcard when wildcards are not supported */
+ context.connectionProperties.isWildcardAvailable = 0U;
+ subscribeInfo.pTopicFilter = "topic/#";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test topic filter with plus wildcard when wildcards are not supported */
+
+ context.connectionProperties.isWildcardAvailable = 0U;
+ subscribeInfo.pTopicFilter = "topic/+/abc";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ subscribeInfo.pTopicFilter = "topic/+/subtopic/#";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+
+ /* Test shared subscription with invalid characters in share name */
+ subscribeInfo.pTopicFilter = "$share/group#/topic";
+ subscribeInfo.topicFilterLength = strlen( subscribeInfo.pTopicFilter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+}
+
+void test_MQTTV5_Subscribe_ValidateFailure( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTSubscribeInfo_t subscribeInfo;
+ MQTTContext_t testContext = { 0 };
- context.connectStatus = MQTTConnected;
+ memset( &subscribeInfo, 0, sizeof( subscribeInfo ) );
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ /* Force the validation function to return an error */
+ validateSubscribeReturn = MQTTBadParameter;
- /* Expect the above calls when running MQTT_Unsubscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ mqttStatus = MQTT_Subscribe( &testContext, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ /* Restore for later tests */
+ validateSubscribeReturn = MQTTSuccess;
}
-/**
- * @brief This test case verifies that MQTT_Unsubscribe does not return success
- * when the connection status is anything but MQTTConnected
- */
-void test_MQTT_Unsubscribe_not_connected( void )
+void test_MQTTV5_Subscribe_happy_path( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
- subscribeInfo.qos = MQTTQoS0;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ MQTTPropBuilder_t propBuilder = { 0 };
+ uint8_t buf[ 500 ];
+ size_t bufLength = sizeof( buf );
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+
+ propBuilder.pBuffer[ 0 ] = 0x0B;
+ propBuilder.pBuffer[ 1 ] = 2;
+ propBuilder.currentIndex = 2;
- /* Test 1 Connection status is MQTTNotConnected*/
- context.connectStatus = MQTTNotConnected;
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- /* Expect the above calls when running MQTT_Unsubscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
- /* Test 2 Connection status is MQTTDisconnectPending*/
- context.connectStatus = MQTTDisconnectPending;
/* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- /* Expect the above calls when running MQTT_Unsubscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
- TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
+ MQTT_ValidateSubscribeProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ context.connectionProperties.isWildcardAvailable = 0U;
+ MQTT_ValidateSubscribeProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ MQTT_ValidateSubscribeProperties_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
}
/**
- * @brief This test case verifies that MQTT_Subscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
+ * @brief This test case verifies that MQTT_Subscribe does not return success if the connect status
+ * is anythin but MQTTConnected.
*/
-void test_MQTT_Unsubscribe_happy_path1( void )
+void test_MQTT_Subscribe_happy_path_not_connected( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 2 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo[ 0 ] );
+ setupSubscriptionInfo( &subscribeInfo );
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- context.connectStatus = MQTTConnected;
-
+ /* Test 1 connect status is MQTTNotConnected */
+ context.connectStatus = MQTTNotConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
-
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ /* Test 2 connect status is MQTTDisconnectPending*/
+ context.connectStatus = MQTTDisconnectPending;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
-/**
- * @brief This test case verifies that MQTT_Subscribe returns successfully
- * when valid parameters are passed and all bytes are sent.
- */
-void test_MQTT_unsubscribe_happy_path2( void )
+void test_MQTTV5_Subscribe_happy_path1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 3 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTSubscribeInfo_t subscribeInfo[ 2 ];
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
- setupSubscriptionInfo( &subscribeInfo[ 0 ] );
- setupSubscriptionInfo( &subscribeInfo[ 1 ] );
- setupSubscriptionInfo( &subscribeInfo[ 2 ] );
- /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
context.connectStatus = MQTTConnected;
- /* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb1 );
+ subscribeInfo[ 0 ].qos = MQTTQoS2;
+ subscribeInfo[ 0 ].pTopicFilter = "abc";
+ subscribeInfo[ 0 ].topicFilterLength = 3;
+ subscribeInfo[ 0 ].noLocalOption = 1;
+ subscribeInfo[ 0 ].retainAsPublishedOption = 1;
+ subscribeInfo[ 0 ].retainHandlingOption = 0;
+
+ subscribeInfo[ 1 ].qos = MQTTQoS0;
+ subscribeInfo[ 1 ].pTopicFilter = "def";
+ subscribeInfo[ 1 ].retainHandlingOption = 2;
+ subscribeInfo[ 1 ].topicFilterLength = 3;
+ subscribeInfo[ 1 ].noLocalOption = 0;
+ subscribeInfo[ 1 ].retainAsPublishedOption = 0;
+
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 3, MQTT_FIRST_VALID_PACKET_ID );
+ mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+
+ subscribeInfo[ 0 ].qos = MQTTQoS0;
+ subscribeInfo[ 0 ].pTopicFilter = "def";
+ subscribeInfo[ 0 ].retainHandlingOption = 2;
+ subscribeInfo[ 0 ].topicFilterLength = 3;
+ subscribeInfo[ 0 ].noLocalOption = 0;
+ subscribeInfo[ 0 ].retainAsPublishedOption = 0;
+
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+
+ mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
+
+ subscribeInfo[ 0 ].qos = 3;
+ subscribeInfo[ 0 ].pTopicFilter = "def";
+ subscribeInfo[ 0 ].retainHandlingOption = 2;
+ subscribeInfo[ 0 ].topicFilterLength = 3;
+ subscribeInfo[ 0 ].noLocalOption = 0;
+ subscribeInfo[ 0 ].retainAsPublishedOption = 0;
+
+ mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+}
+
+void test_MQTTV5_Subscribe_happy_path2( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ context.connectionProperties.isSharedAvailable = 1;
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ subscribeInfo.qos = MQTTQoS1;
+ subscribeInfo.pTopicFilter = "$share/abc/bcd";
+ subscribeInfo.topicFilterLength = 14;
+ subscribeInfo.noLocalOption = 0;
+ subscribeInfo.retainAsPublishedOption = 1;
+ subscribeInfo.retainHandlingOption = 0;
+
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
}
-void test_MQTT_Unsubscribe_MultipleSubscriptions( void )
+void test_MQTT_Subscribe_MultipleSubscriptions( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- MQTTSubscribeInfo_t subscribeInfo[ 5 ];
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTSubscribeInfo_t subscribeInfo[ 4 ];
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH + 2;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
@@ -6388,431 +8262,1066 @@ void test_MQTT_Unsubscribe_MultipleSubscriptions( void )
"This test is configured to work with MQTT_SUB_UNSUB_MAX_VECTORS defined as 6." );
setupTransportInterface( &transport );
- transport.writev = transportWritevUnsubscribeSuccess;
+ transport.writev = transportWritevSubscribeSuccess;
setupNetworkBuffer( &networkBuffer );
subscribeInfo[ 0 ].qos = MQTTQoS1;
subscribeInfo[ 0 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
subscribeInfo[ 0 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
+ subscribeInfo[ 0 ].noLocalOption = 0;
+ subscribeInfo[ 0 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 0 ].retainHandlingOption = retainSendOnSub;
subscribeInfo[ 1 ].qos = MQTTQoS2;
subscribeInfo[ 1 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER1;
subscribeInfo[ 1 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH1;
+ subscribeInfo[ 1 ].noLocalOption = 0;
+ subscribeInfo[ 1 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 1 ].retainHandlingOption = retainSendOnSub;
subscribeInfo[ 2 ].qos = MQTTQoS0;
subscribeInfo[ 2 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER2;
subscribeInfo[ 2 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH2;
+ subscribeInfo[ 2 ].noLocalOption = 0;
+ subscribeInfo[ 2 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 2 ].retainHandlingOption = retainSendOnSub;
subscribeInfo[ 3 ].qos = MQTTQoS1;
subscribeInfo[ 3 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER3;
subscribeInfo[ 3 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH3;
+ subscribeInfo[ 3 ].noLocalOption = 0;
+ subscribeInfo[ 3 ].retainAsPublishedOption = 0;
+ subscribeInfo[ 3 ].retainHandlingOption = retainSendOnSub;
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
- &incomingRecords, 4 );
+ &incomingRecords, 4, NULL, 0 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribedHeader_cb2 );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb2 );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
/* Expect the above calls when running MQTT_Subscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID );
+ mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID, NULL );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+}
+
+void test_MQTTV5_Subscribe_happy_path3( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ context.connectionProperties.isSharedAvailable = 1;
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ subscribeInfo.qos = MQTTQoS1;
+ subscribeInfo.pTopicFilter = "$share/abc/def";
+ subscribeInfo.topicFilterLength = 14;
+ subscribeInfo.noLocalOption = 0;
+ subscribeInfo.retainAsPublishedOption = 1;
+ subscribeInfo.retainHandlingOption = 0;
+
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
}
/**
- * @brief This test case verifies that MQTT_Unsubscribe returns MQTTSendFailed
+ * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
-void test_MQTT_Unsubscribe_error_path1( void )
+void test_MQTT_Subscribe_error_paths1( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
/* Verify that an error is propagated when transport interface returns an error. */
- setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
-
+ setupTransportInterface( &transport );
transport.send = transportSendFailure;
- transport.recv = transportRecvFailure;
transport.writev = NULL;
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
/* Verify MQTTSendFailed is propagated when transport interface returns an error. */
- MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
- MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- /* Expect the above calls when running MQTT_Unsubscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
-
- /* Case when there is timeout in sending data through transport send. */
}
/**
* @brief This test case verifies that MQTT_Unsubscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
-void test_MQTT_Unsubscribe_error_path2( void )
+void test_MQTT_Unsubscribe_error_paths1( void )
{
- MQTTStatus_t mqttStatus;
+ MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
- size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
- size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ /* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
-
- /* Verify that an error is propagated when transport interface returns an error. */
setupTransportInterface( &transport );
transport.send = transportSendFailure;
- transport.recv = transportRecvFailure;
transport.writev = NULL;
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
- MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
- transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
+ /* Verify MQTTSendFailed is propagated when transport interface returns an error. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
- /* Expect the above calls when running MQTT_Unsubscribe. */
- mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
+ serializeUnsubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
}
-/* ========================================================================== */
-
-/**
- * @brief This test case verifies that MQTT_Ping returns MQTTBadParameter
- * with context parameter is NULL.
- */
-void test_MQTT_Ping_invalid_params( void )
-{
- MQTTStatus_t mqttStatus;
-
- /* Call ping with a NULL context. */
- mqttStatus = MQTT_Ping( NULL );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
-
/**
- * @brief This test case verifies that MQTT_Ping returns successfully
- * when valid parameters are passed and all bytes are sent.
+ * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
+ * if transport interface send fails and timer overflows.
*/
-void test_MQTT_Ping_happy_path( void )
+void test_MQTT_Subscribe_error_paths_timerOverflowCheck( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
- setupTransportInterface( &transport );
+ globalEntryTime = UINT32_MAX - 2U;
+
+ /* The timer function can be called a maximum of these many times
+ * (which is way less than UINT32_MAX). This ensures that if overflow
+ * check is not correct, then the timer mock call will fail and assert. */
+ getTimeMockCallLimit = MQTT_SEND_TIMEOUT_MS + 1;
+
+ /* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+ setupTransportInterface( &transport );
+ transport.writev = NULL;
+ /* Case when there is timeout in sending data through transport send. */
+ transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTimeMock, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
- /* Verify MQTTSuccess is returned. */
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Expect the above calls when running MQTT_Ping. */
- mqttStatus = MQTT_Ping( &context );
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
- TEST_ASSERT_EQUAL( context.lastPacketTxTime, context.pingReqSendTimeMs );
- TEST_ASSERT_TRUE( context.waitingForPingResp );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+ TEST_ASSERT_EQUAL( -1, getTimeMockCallLimit );
}
/**
- * @brief This test case verifies that MQTT_Ping does not returns success
- * if the connection status is anything but MQTTConnect.
+ * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
+ * if transport interface send fails and timer overflows.
*/
-void test_MQTT_Ping_not_connected( void )
+void test_MQTT_Subscribe_error_paths_timerOverflowCheck1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
- setupTransportInterface( &transport );
+ globalEntryTime = UINT32_MAX - MQTT_SEND_TIMEOUT_MS + 1;
+
+ /* The timer function can be called a exactly 2 times. First when setting
+ * the initial time, next time when checking for timeout.
+ */
+ getTimeMockBigTimeStepCallLimit = 2;
+
+ /* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+ setupTransportInterface( &transport );
+ transport.writev = NULL;
+ /* Case when there is timeout in sending data through transport send. */
+ transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
- mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTimeMockBigTimeStep, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- /* Test 1 when the connection status is MQTTNotConnected*/
- context.connectStatus = MQTTNotConnected;
- /* Verify MQTTSuccess is returned. */
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Expect the above calls when running MQTT_Ping. */
- mqttStatus = MQTT_Ping( &context );
- TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
+ context.connectStatus = MQTTConnected;
- /* Test 2 when the connection status is MQTTDisconnectPending*/
- context.connectStatus = MQTTDisconnectPending;
- /* Verify MQTTSuccess is returned. */
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Expect the above calls when running MQTT_Ping. */
- mqttStatus = MQTT_Ping( &context );
- TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+ TEST_ASSERT_EQUAL( -1, getTimeMockBigTimeStepCallLimit );
}
/**
- * @brief This test case verifies that MQTT_Ping returns MQTTSendFailed
+ * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
-void test_MQTT_Ping_error_path( void )
+void test_MQTT_Subscribe_error_paths2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
- size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
- setupTransportInterface( &transport );
+ /* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
-
- /* Test a network error is returned from sending the PING packet over the
- * transport send . */
- transport.send = transportSendFailure;
- transport.recv = transportRecvFailure;
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+ setupTransportInterface( &transport );
+ transport.writev = NULL;
+ /* Case when there is timeout in sending data through transport send. */
+ transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
- /* Verify MQTTSendFailed is propagated when transport interface returns an error. */
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Expect the above calls when running MQTT_Ping. */
- mqttStatus = MQTT_Ping( &context );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+}
+
+/**
+ * @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
+ * if transport interface fails to send and the connection status is converted to
+ * MQTTDisconnectPending
+ */
+void test_MQTT_Subscribe_error_paths_with_transport_failure( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ /* Verify that an error is propagated when transport interface returns an error. */
+ setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+ setupTransportInterface( &transport );
+ transport.writev = NULL;
+ transport.send = transportSendFailure;
- /* Case when there is timeout in sending data through transport send. */
- transport.recv = transportRecvSuccess;
- transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Verify that the API returns failure. */
- mqttStatus = MQTT_Ping( &context );
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+ TEST_ASSERT_EQUAL( MQTTDisconnectPending, context.connectStatus );
+}
+void test_MQTTV5_shared_subscriptions( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
- /* Initialize context. */
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ context.connectionProperties.isSharedAvailable = 1;
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-
context.connectStatus = MQTTConnected;
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- /* Verify MQTTBadParameter is propagated when getting PINGREQ packet size fails. */
- MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
- MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
- /* Expect the above calls when running MQTT_Ping. */
- mqttStatus = MQTT_Ping( &context );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
+ subscribeInfo.pTopicFilter = "$share/abc/bcd";
+ subscribeInfo.topicFilterLength = 14;
+ subscribeInfo.noLocalOption = 0;
+ subscribeInfo.retainAsPublishedOption = 1;
+ subscribeInfo.retainHandlingOption = 0;
+ subscribeInfo.qos = MQTTQoS2;
-/* ========================================================================== */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, mqttStatus );
-/**
- * @brief Test MQTT_MatchTopic for invalid input parameters.
- */
-void test_MQTT_MatchTopic_InvalidInput( void )
-{
- bool matchResult = false;
+ subscribeInfo.qos = MQTTQoS1;
+ subscribeInfo.retainHandlingOption = 3;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+ subscribeInfo.retainHandlingOption = 0;
- /* NULL topic name. */
- TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( NULL,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
- /* Invalid topic name length. */
- TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
- 0u,
- MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
- /* NULL topic filter. */
- TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- NULL,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ /** Invalid Sharename */
+ subscribeInfo.pTopicFilter = "$share/abc";
+ subscribeInfo.topicFilterLength = 10;
- /* Invalid topic filter length. */
- TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- MQTT_SAMPLE_TOPIC_FILTER,
- 0u,
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
- /* Invalid output parameter. */
- TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- NULL ) );
+ subscribeInfo.pTopicFilter = "$share/abc/bcd";
+ subscribeInfo.topicFilterLength = 14;
+ subscribeInfo.noLocalOption = 1;
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, mqttStatus );
+}
+
+/* Suback - Unsuback Happy path */
+void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths_suback( void )
+{
+ MQTTStatus_t status;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_SUBACK;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ status = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ modifyIncomingPacketStatus = MQTTSuccess;
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &context );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
+/* ========================================================================== */
+
/**
- * @brief Verifies that MQTT_MatchTopic is able to determine an exact match between the
- * topic name and topic filter.
+ * @brief This test case verifies that MQTT_Unsubscribe returns MQTTBadParameter
+ * with an invalid parameter. This test case also gives us coverage over
+ * the private method, validateSubscribeUnsubscribeParams(...).
*/
-void test_MQTT_MatchTopic_ExactMatch( void )
+void test_MQTT_Unsubscribe_invalid_params( void )
{
- const char * pTopicFilter = NULL;
- const char * pTopicName = NULL;
- bool matchResult = false;
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
- /* Test for topic filter and topic name having exact match. */
- pTopicName = "/test/match";
- pTopicFilter = "/test/match";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ /* Call subscribe with a NULL context. */
+ mqttStatus = MQTT_Unsubscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
- /* Test for exact match when topic name and filter start with '$' .*/
- pTopicName = "$///";
- pTopicFilter = "$///";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ /* Call subscribe with a NULL subscription list. */
+ mqttStatus = MQTT_Unsubscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
- /* Test for no match (with no wildcard in the topic filter). */
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- MQTT_SAMPLE_TOPIC_FILTER,
- MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ /* Call subscribe with 0 subscriptions. */
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
- /* Edge case tests (for branch coverage) to match at end with no wildcards. */
- pTopicName = "/test/match/";
- pTopicFilter = "/test/match/a";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ /* Packet ID cannot be 0 per MQTT 5.0 spec. */
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, 0, NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
- pTopicName = "a";
- pTopicFilter = "a/";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
- /* Edge case test (for branch coverage) when topic name has more levels
- * than topic filter. */
- pTopicName = "test/match";
- pTopicFilter = "test";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+static uint8_t * MQTTV5_SerializeUnsubscribeHeader_cb( uint32_t remainingLength,
+ uint8_t * pIndex,
+ uint16_t packetId,
+ int numcallbacks )
+{
+ ( void ) remainingLength;
+ ( void ) pIndex;
+ ( void ) packetId;
+ ( void ) numcallbacks;
+
+ return pIndex;
}
/**
- * @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification of all
- * cases of matching topic filters that contain the single-level '+' wildcard.
+ * @brief This test case verifies that MQTT_Unsubscribe returns successfully
+ * when valid parameters are passed and all bytes are sent.
*/
-void test_MQTT_MatchTopic_Wildcard_SingleLevel_Match_Cases( void )
+void test_MQTT_Unsubscribe_happy_path( void )
{
- const char * pTopicName = NULL;
- const char * pTopicFilter = NULL;
- bool matchResult = false;
-
- /* Nominal case of topic filter ending with '+' .*/
- pTopicName = "/test/match/level1";
- pTopicFilter = "/test/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
- /* Test for match with a topic name starting with '$' .*/
- pTopicName = "$test/match/level1";
- pTopicFilter = "$test/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ serializeUnsubscribeHeader_Stub( MQTTV5_SerializeUnsubscribeHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+ MQTT_ValidateUnsubscribeProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+
+ /* Expect the above calls when running MQTT_Unsubscribe. */
+
+ MQTTPropBuilder_t propBuilder = { 0 };
+ uint8_t buf[ 500 ];
+ size_t bufLength = sizeof( buf );
+ propBuilder.pBuffer = buf;
+ propBuilder.bufferLength = bufLength;
+
+ propBuilder.currentIndex = 10;
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ propBuilder.pBuffer = NULL;
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ propBuilder.pBuffer = buf;
+
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ /*Simulate Failure of MQTT_ValidateUnsubscribeProperties. */
+ MQTT_ValidateUnsubscribeProperties_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
+void test_MQTT_Unsubscribe_MultipleSubscriptions( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo[ 5 ];
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+ uint8_t buf[ 100 ];
+
+ TEST_ASSERT_EQUAL_MESSAGE( 6U, MQTT_SUB_UNSUB_MAX_VECTORS,
+ "This test is configured to work with MQTT_SUB_UNSUB_MAX_VECTORS defined as 6." );
+
+ setupTransportInterface( &transport );
+ transport.writev = transportWritevUnsubscribeSuccess;
+
+ setupNetworkBuffer( &networkBuffer );
+
+ subscribeInfo[ 0 ].qos = MQTTQoS1;
+ subscribeInfo[ 0 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
+ subscribeInfo[ 0 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
+
+ subscribeInfo[ 1 ].qos = MQTTQoS2;
+ subscribeInfo[ 1 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER1;
+ subscribeInfo[ 1 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH1;
+
+ subscribeInfo[ 2 ].qos = MQTTQoS0;
+ subscribeInfo[ 2 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER2;
+ subscribeInfo[ 2 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH2;
+
+ subscribeInfo[ 3 ].qos = MQTTQoS1;
+ subscribeInfo[ 3 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER3;
+ subscribeInfo[ 3 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH3;
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, buf, 0 );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ context.connectStatus = MQTTConnected;
+
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribedHeader_cb2 );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID, NULL );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+}
+
+void test_MQTT_Unsubscribe_happy_path_withUP( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ serializeUnsubscribeHeader_Stub( MQTTV5_SerializeUnsubscribeHeader_cb );
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+}
+
+void test_MQTTV5_Unsubscribe_happy_path( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+ MQTTPubAckInfo_t incomingRecords = { 0 };
+ MQTTPubAckInfo_t outgoingRecords = { 0 };
+
+ uint8_t ackPropsBuf[ 500 ];
+ size_t ackPropsBufLength = sizeof( ackPropsBuf );
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ context.ackPropsBuffer = ackPropsBuffer;
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_InitStatefulQoS( &context,
+ &outgoingRecords, 4,
+ &incomingRecords, 4, ackPropsBuf, ackPropsBufLength );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
+
+ /* Expect the above calls when running MQTT_Subscribe. */
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ /*With NULL buffer of propBuilder. */
+ MQTTPropBuilder_t propBuilder;
+ propBuilder.pBuffer = NULL;
+ MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, &propBuilder );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+}
+
+/**
+ * @brief This test case verifies that MQTT_Unsubscribe does not return success
+ * when the connection status is anything but MQTTConnected
+ */
+void test_MQTT_Unsubscribe_not_connected( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTSubscribeInfo_t subscribeInfo = { 0 };
+ uint32_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ uint32_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ setupSubscriptionInfo( &subscribeInfo );
+ subscribeInfo.qos = MQTTQoS0;
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ /* Test 1 Connection status is MQTTNotConnected*/
+ context.connectStatus = MQTTNotConnected;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ /* Expect the above calls when running MQTT_Unsubscribe. */
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
+
+ /* Test 2 Connection status is MQTTDisconnectPending*/
+ context.connectStatus = MQTTDisconnectPending;
+ /* Verify MQTTSuccess is returned with the following mocks. */
+ MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
+ serializeSubscribeHeader_Stub( MQTTV5_SerializeSubscribedHeader_cb );
+ /* Expect the above calls when running MQTT_Unsubscribe. */
+ mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID, NULL );
+ TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
+}
+
+
+void test_MQTT_Ping_invalid_params( void )
+{
+ MQTTStatus_t mqttStatus;
+
+ /* Call ping with a NULL context. */
+ mqttStatus = MQTT_Ping( NULL );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
+/**
+ * @brief This test case verifies that MQTT_Ping returns successfully
+ * when valid parameters are passed and all bytes are sent.
+ */
+void test_MQTT_Ping_happy_path( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ uint32_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSuccess is returned. */
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Expect the above calls when running MQTT_Ping. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ TEST_ASSERT_EQUAL( context.lastPacketTxTime, context.pingReqSendTimeMs );
+ TEST_ASSERT_TRUE( context.waitingForPingResp );
+}
+
+/**
+ * @brief This test case verifies that MQTT_Ping does not returns success
+ * if the connection status is anything but MQTTConnect.
+ */
+void test_MQTT_Ping_not_connected( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ uint32_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ /* Test 1 when the connection status is MQTTNotConnected*/
+ context.connectStatus = MQTTNotConnected;
+ /* Verify MQTTSuccess is returned. */
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Expect the above calls when running MQTT_Ping. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
+
+ /* Test 2 when the connection status is MQTTDisconnectPending*/
+ context.connectStatus = MQTTDisconnectPending;
+ /* Verify MQTTSuccess is returned. */
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Expect the above calls when running MQTT_Ping. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
+}
+
+
+/**
+ * @brief This test case verifies that MQTT_Ping returns MQTTSendFailed
+ * if transport interface send returns an error.
+ */
+void test_MQTT_Ping_error_path( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ uint32_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ /* Test a network error is returned from sending the PING packet over the
+ * transport send . */
+ transport.send = transportSendFailure;
+ transport.recv = transportRecvFailure;
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ /* Verify MQTTSendFailed is propagated when transport interface returns an error. */
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Expect the above calls when running MQTT_Ping. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+
+ /* Case when there is timeout in sending data through transport send. */
+ transport.recv = transportRecvSuccess;
+ transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ context.connectStatus = MQTTConnected;
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
+ /* Verify that the API returns failure. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
+
+
+ /* Initialize context. */
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+ /* Verify MQTTBadParameter is propagated when getting PINGREQ packet size fails. */
+ MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
+ /* Expect the above calls when running MQTT_Ping. */
+ mqttStatus = MQTT_Ping( &context );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+
+/**
+ * @brief Test MQTT_MatchTopic for invalid input parameters.
+ */
+void test_MQTT_MatchTopic_InvalidInput( void )
+{
+ bool matchResult = false;
+
+ /* NULL topic name. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( NULL,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic name length. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
+ 0u,
+ MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* NULL topic filter. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ NULL,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic filter length. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ MQTT_SAMPLE_TOPIC_FILTER,
+ 0u,
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid output parameter. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ NULL ) );
+}
+
+/**
+ * @brief Verifies that MQTT_MatchTopic is able to determine an exact match between the
+ * topic name and topic filter.
+ */
+void test_MQTT_MatchTopic_ExactMatch( void )
+{
+ const char * pTopicFilter = NULL;
+ const char * pTopicName = NULL;
+ bool matchResult = false;
+
+ /* Test for topic filter and topic name having exact match. */
+ pTopicName = "/test/match";
+ pTopicFilter = "/test/match";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test for exact match when topic name and filter start with '$' .*/
+ pTopicName = "$///";
+ pTopicFilter = "$///";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test for no match (with no wildcard in the topic filter). */
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ MQTT_SAMPLE_TOPIC_FILTER,
+ MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Edge case tests (for branch coverage) to match at end with no wildcards. */
+ pTopicName = "/test/match/";
+ pTopicFilter = "/test/match/a";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ pTopicName = "a";
+ pTopicFilter = "a/";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Edge case test (for branch coverage) when topic name has more levels
+ * than topic filter. */
+ pTopicName = "test/match";
+ pTopicFilter = "test";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+}
+
+/**
+ * @brief Verifies that MQTT_MatchTopic meets the MQTT 5.0 specification of all
+ * cases of matching topic filters that contain the single-level '+' wildcard.
+ */
+void test_MQTT_MatchTopic_Wildcard_SingleLevel_Match_Cases( void )
+{
+ const char * pTopicName = NULL;
+ const char * pTopicFilter = NULL;
+ bool matchResult = false;
+
+ /* Nominal case of topic filter ending with '+' .*/
+ pTopicName = "/test/match/level1";
+ pTopicFilter = "/test/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test for match with a topic name starting with '$' .*/
+ pTopicName = "$test/match/level1";
+ pTopicFilter = "$test/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
/* Test with '+' as the topic filter. */
pTopicName = "test";
@@ -6824,647 +9333,1233 @@ void test_MQTT_MatchTopic_Wildcard_SingleLevel_Match_Cases( void )
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
- /* Test that '+' in topic filter matches topic name containing consecutive
- * level separators, "//" in the corresponding level. */
- pTopicName = "/test//level1";
- pTopicFilter = "/test/+/level1";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ /* Test that '+' in topic filter matches topic name containing consecutive
+ * level separators, "//" in the corresponding level. */
+ pTopicName = "/test//level1";
+ pTopicFilter = "/test/+/level1";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test with multiple placements of wildcard in topic filter. */
+ pTopicName = "/test/match/level1";
+ pTopicFilter = "/+/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ pTopicName = "/test/match/level1";
+ pTopicFilter = "+/+/+/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ pTopicName = "/test///level1";
+ pTopicFilter = "/test/+/+/level1";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test that match fails when topic name has more levels than topic filter. */
+ pTopicName = "/test/match/level1/level2";
+ pTopicFilter = "/test/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ pTopicName = "/";
+ pTopicFilter = "+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Edge case where filter ending with '/+' matches topic ending with '/'. */
+ pTopicName = "/test/match/";
+ pTopicFilter = "/test/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+}
+
+/**
+ * @brief Verifies that MQTT_MatchTopic meets the MQTT 5.0 specification for
+ * cases of where topic filter containing '+' wildcard do not match topic name.
+ */
+void test_MQTT_MatchTopic_Wildcard_SingleLevel_No_Match_Cases( void )
+{
+ const char * pTopicName = NULL;
+ const char * pTopicFilter = NULL;
+ bool matchResult = false;
+
+ /* Edge case where filter ending with '/+' should not match a topic ending with
+ * at parent level. */
+ pTopicName = "/test/match";
+ pTopicFilter = "/test/match/+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Edge case where topic filter starts with '+' and topic name starts with '$'. */
+ pTopicName = "$/test/match";
+ pTopicFilter = "+/test/match";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Topic name matches all characters with topic filter, but topic filter is invalid. */
+ pTopicName = "test/match/level";
+ pTopicFilter = "test/match/level+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic filter where non-starting '+' is not placed after '/'.*/
+ pTopicName = "test/match/level1";
+ pTopicFilter = "test/match/level+";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic filter where intermediate '+' is not followed by '/'.*/
+ pTopicName = "test/match/level";
+ pTopicFilter = "test/+?level";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+}
+
+/**
+ * @brief Verifies that MQTT_MatchTopic meets the MQTT 5.0 specification of all
+ * cases of matching topic filters that contain the multi-level '#' wildcard.
+ */
+void test_MQTT_MatchTopic_Wildcard_MultiLevel_Match_Cases( void )
+{
+ const char * pTopicName = NULL;
+ const char * pTopicFilter = NULL;
+ bool matchResult = false;
+
+ /* Match topic filter ending with '#' with a single level .*/
+ pTopicName = "/test/match/level1";
+ pTopicFilter = "/test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Match topic filter ending with '#' with multiple levels in topic name.*/
+ pTopicName = "/test/match/level1/level2/level3";
+ pTopicFilter = "/test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ pTopicName = "/test/match/level1/level2/level3";
+ pTopicFilter = "/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Match when topic filter is "#" */
+ pTopicName = "test/match/level";
+ pTopicFilter = "#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test for match with a topic name starting with '$' .*/
+ pTopicName = "$test/match/level1";
+ pTopicFilter = "$test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Match '#' with topic name ending at the parent level. */
+ pTopicName = "/test/match";
+ pTopicFilter = "/test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Edge case where filter ending with '/#' matches topic ending with '/'. */
+ pTopicName = "/test/match/";
+ pTopicFilter = "/test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ /* Test for topic filters containing both '+' and '#' wildcard characters. */
+ pTopicName = "/test/match";
+ pTopicFilter = "+/test/match/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+
+ pTopicName = "/test/match/level";
+ pTopicFilter = "+/+/+/#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( true, matchResult );
+}
+
+/**
+ * @brief Verifies that MQTT_MatchTopic meets the MQTT 5.0 specification for
+ * cases of where topic filter containing '#' wildcard do not match topic name.
+ */
+void test_MQTT_MatchTopic_Wildcard_MultiLevel_No_Match_Cases( void )
+{
+ const char * pTopicName = NULL;
+ const char * pTopicFilter = NULL;
+ bool matchResult = false;
+
+ /* Edge case where topic filter starts with '#' and topic name starts with '$'. */
+ pTopicName = "$/test/match";
+ pTopicFilter = "#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic filter where non-starting '#' is not placed after '/'.*/
+ pTopicName = "test/match/level1";
+ pTopicFilter = "test/match/level#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Topic name matches all characters with topic filter, but topic filter is invalid. */
+ pTopicName = "test/match/level";
+ pTopicFilter = "test/match/level?#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ pTopicName = "test/match/level";
+ pTopicFilter = "test/match/level#";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ /* Invalid topic filters that contain '#' at a non-ending position .*/
+ pTopicName = "test/match/level1/level2";
+ pTopicFilter = "test/match/#/level2";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+
+ pTopicName = "test/match/level2";
+ pTopicFilter = "#/match/level2";
+ TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
+ strlen( pTopicName ),
+ pTopicFilter,
+ strlen( pTopicFilter ),
+ &matchResult ) );
+ TEST_ASSERT_EQUAL( false, matchResult );
+}
+
+void test_MQTT_MatchTopic_topicNameLength_Overflow( void )
+{
+ const char * pTopicName = "topic";
+ size_t topicNameLength = 65536;
+ const char * pTopicFilter = "#/match/level2";
+ size_t topicFilterlen = 14;
+ bool matchResult = false;
+
+ /* Topic name length more than maximum allowed length. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( pTopicName,
+ topicNameLength,
+ pTopicFilter,
+ topicFilterlen,
+ &matchResult ) );
+}
+
+void test_MQTT_MatchTopic_topicFilterLength_Overflow( void )
+{
+ const char * pTopicName = "topic";
+ size_t topicNameLength = 5;
+ const char * pTopicFilter = "#/match/level2";
+ size_t topicFilterlen = 65536;
+ bool matchResult = false;
+
+ /* Topic filter length more than maximum allowed length. */
+ TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( pTopicName,
+ topicNameLength,
+ pTopicFilter,
+ topicFilterlen,
+ &matchResult ) );
+}
+
+/**
+ * @brief Tests that MQTT_GetSubAckStatusCodes works as expected in parsing the
+ * payload information of a SUBACK packet.
+ */
+void test_MQTT_GetSubAckStatusCodes( void )
+{
+ MQTTPacketInfo_t mqttPacketInfo = { 0 };
+ size_t payloadSize;
+ uint8_t * pPayloadStart;
+ MQTTStatus_t status = MQTTSuccess;
+ uint8_t buffer[ 10 ] = { 0 };
+
+ buffer[ 0 ] = 0;
+ buffer[ 1 ] = 1;
+ buffer[ 2 ] = 0; /*Length of the properties is 0. */
+ buffer[ 3 ] = 0x00;
+ buffer[ 4 ] = 0x01;
+ buffer[ 5 ] = 0x02;
+ buffer[ 6 ] = 0x80;
+
+ /* Process a valid SUBACK packet containing whole range of server response codes. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
+ mqttPacketInfo.pRemainingData = buffer;
+
+ mqttPacketInfo.remainingLength = MQTT_REMAINING_LENGTH_INVALID;
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ mqttPacketInfo.remainingLength = 7;
+
+ /* decodeSubackProperties fails. */
+ decodeSubackPropertyLength_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* decodeSubackProperties succeeds. */
+ decodeSubackPropertyLength_Stub( decodeSubackPropertyLength_cb );
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL_PTR( &buffer[ 3 ], pPayloadStart );
+ TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos0, pPayloadStart[ 0 ] );
+ TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos1, pPayloadStart[ 1 ] );
+ TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos2, pPayloadStart[ 2 ] );
+ TEST_ASSERT_EQUAL_INT( MQTTSubAckFailure, pPayloadStart[ 3 ] );
+ TEST_ASSERT_EQUAL_INT( 4, payloadSize );
+
+ /* Packet is NULL. */
+ status = MQTT_GetSubAckStatusCodes( NULL, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Test with multiple placements of wildcard in topic filter. */
- pTopicName = "/test/match/level1";
- pTopicFilter = "/+/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ /* Output parameter, pPayloadStart, is NULL. */
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, NULL, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Output parameter, pPayloadSize, is NULL. */
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Remaining Data is NULL. */
+ mqttPacketInfo.pRemainingData = NULL;
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* non-SUBACK packet type. */
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_CONNACK;
+ mqttPacketInfo.pRemainingData = buffer;
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ /* Invalid remaining length value in packet. */
+ mqttPacketInfo.remainingLength = 0;
+ mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
+ status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
+
+/**
+ * @brief Test MQTT_Status_strerror returns correct strings.
+ */
+void test_MQTT_Status_strerror( void )
+{
+ MQTTStatus_t status;
+ const char * str = NULL;
+
+ status = MQTTSuccess;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTSuccess", str );
+
+ status = MQTTBadParameter;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTBadParameter", str );
+
+ status = MQTTNoMemory;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTNoMemory", str );
+
+ status = MQTTSendFailed;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTSendFailed", str );
+
+ status = MQTTRecvFailed;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTRecvFailed", str );
+
+ status = MQTTBadResponse;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTBadResponse", str );
+
+ status = MQTTServerRefused;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTServerRefused", str );
+
+ status = MQTTNoDataAvailable;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTNoDataAvailable", str );
+
+ status = MQTTIllegalState;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTIllegalState", str );
+
+ status = MQTTStateCollision;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTStateCollision", str );
+
+ status = MQTTKeepAliveTimeout;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTKeepAliveTimeout", str );
+
+ status = MQTTNeedMoreBytes;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "MQTTNeedMoreBytes", str );
+
+ status = MQTTNeedMoreBytes + 1;
+ str = MQTT_Status_strerror( status );
+ TEST_ASSERT_EQUAL_STRING( "Invalid MQTT Status code", str );
+}
+
+/* ========================================================================== */
+void test_MQTT_GetPacketId_NULL_Context( void )
+{
+ uint16_t packetId = 0U;
+
+ packetId = MQTT_GetPacketId( NULL );
+
+ TEST_ASSERT_EQUAL( 0, packetId );
+}
+/* ========================================================================== */
+
+void test_MQTT_GetPacketId_happy_path( void )
+{
+ uint16_t packetId = 0U;
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttContext.nextPacketId = 5;
+
+ packetId = MQTT_GetPacketId( &mqttContext );
+
+ TEST_ASSERT_EQUAL( 5, packetId );
+ TEST_ASSERT_EQUAL( 6, mqttContext.nextPacketId );
+}
+
+/* ========================================================================== */
+void test_MQTT_GetPacketId_happy_path_uint16_max( void )
+{
+ uint16_t packetId = 0U;
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttContext.nextPacketId = UINT16_MAX;
+
+ packetId = MQTT_GetPacketId( &mqttContext );
+
+ TEST_ASSERT_EQUAL( UINT16_MAX, packetId );
+ TEST_ASSERT_EQUAL( 1, mqttContext.nextPacketId );
+}
+/* ========================================================================== */
+
+void test_MQTT_CancelCallback_null_context( void )
+{
+ uint16_t packetId = 0U;
+ MQTTStatus_t mqttStatus;
+
+ mqttStatus = MQTT_CancelCallback( NULL, packetId );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
+
+void test_MQTT_CancelCallback_null_outgoingPublishRecords( void )
+{
+ uint16_t packetId = 0U;
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttContext.outgoingPublishRecords = NULL;
+
+ mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
+
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
+
+void test_MQTT_CancelCallback_happy_path( void )
+{
+ uint16_t packetId = 0U;
+ MQTTStatus_t mqttStatus;
+ MQTTContext_t mqttContext = { 0 };
+
+ MQTT_InitConnect_Stub( initConnectProperties_cb );
+ mqttContext.outgoingPublishRecords = NULL;
+ setUPContext( &mqttContext );
+
+ MQTT_RemoveStateRecord_ExpectAndReturn( &mqttContext, packetId, MQTTSuccess );
+ mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
+
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+}
+/* ========================================================================== */
+
+void test_MQTT_InitStatefulQoS_fail_null_context( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
+ MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+
+ mqttStatus = MQTT_InitStatefulQoS( NULL,
+ pOutgoingPublishRecords,
+ 10,
+ pIncomingPublishRecords,
+ 10, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
+
+void test_MQTT_InitStatefulQoS_zero_outgoing_size( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
+ MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
+ pOutgoingPublishRecords,
+ 0,
+ pIncomingPublishRecords,
+ 10, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
+void test_MQTT_InitStatefulQoS_zero_incoming_size( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
+ MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
+ pOutgoingPublishRecords,
+ 10,
+ pIncomingPublishRecords,
+ 0, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
+
+void test_MQTT_InitStatefulQoS_callback_is_null( void )
+{
+ MQTTStatus_t mqttStatus;
+ MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
+ MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+
+ MQTTContext_t mqttContext = { 0 };
+
+ mqttContext.appCallback = NULL;
+
+ mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
+ pOutgoingPublishRecords,
+ 10,
+ pIncomingPublishRecords,
+ 10, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+
+ mqttContext.appCallback = eventCallback2;
+ mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
+ pOutgoingPublishRecords, 4,
+ pIncomingPublishRecords, 4, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
+
+ uint8_t buffer[ 10 ];
+ size_t bufLength = sizeof( buffer );
+ MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTBadParameter );
+ mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
+ pOutgoingPublishRecords, 4,
+ pIncomingPublishRecords, 4, buffer, bufLength );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+}
+/* ========================================================================== */
- pTopicName = "/test/match/level1";
- pTopicFilter = "+/+/+/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+MQTTStatus_t decode_utf8_Stub( void )
+{
+ return MQTTSuccess;
+}
- pTopicName = "/test///level1";
- pTopicFilter = "/test/+/+/level1";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+void test_validatePublish( void )
+{
+ MQTTStatus_t status = MQTTSuccess;
- /* Test that match fails when topic name has more levels than topic filter. */
- pTopicName = "/test/match/level1/level2";
- pTopicFilter = "/test/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ status = MQTT_Publish( NULL, NULL, 2, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- pTopicName = "/";
- pTopicFilter = "+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ MQTTPublishInfo_t publishInfo = { 0 };
+ MQTTContext_t context = { 0 };
+ publishInfo.qos = 2;
+ status = MQTT_Publish( &context, &publishInfo, 0, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* Edge case where filter ending with '/+' matches topic ending with '/'. */
- pTopicName = "/test/match/";
- pTopicFilter = "/test/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ publishInfo.qos = 0;
+ publishInfo.payloadLength = 10;
+ publishInfo.pPayload = NULL;
+ status = MQTT_Publish( &context, &publishInfo, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+
+ publishInfo.pPayload = "abc";
+ publishInfo.payloadLength = 3;
+ publishInfo.qos = 2;
+ status = MQTT_Publish( &context, &publishInfo, 10, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
-/**
- * @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification for
- * cases of where topic filter containing '+' wildcard do not match topic name.
- */
-void test_MQTT_MatchTopic_Wildcard_SingleLevel_No_Match_Cases( void )
+/* ========================================================================== */
+
+void test_MQTT_GetBytesInMQTTVec( void )
{
- const char * pTopicName = NULL;
- const char * pTopicFilter = NULL;
- bool matchResult = false;
+ TransportOutVector_t pTransportArray[ 10 ] =
+ {
+ { .iov_base = NULL, .iov_len = 1 },
+ { .iov_base = NULL, .iov_len = 2 },
+ { .iov_base = NULL, .iov_len = 3 },
+ { .iov_base = NULL, .iov_len = 4 },
+ { .iov_base = NULL, .iov_len = 5 },
+ { .iov_base = NULL, .iov_len = 6 },
+ { .iov_base = NULL, .iov_len = 7 },
+ { .iov_base = NULL, .iov_len = 8 },
+ { .iov_base = NULL, .iov_len = 9 },
+ { .iov_base = NULL, .iov_len = 10 },
+ };
- /* Edge case where filter ending with '/+' should not match a topic ending with
- * at parent level. */
- pTopicName = "/test/match";
- pTopicFilter = "/test/match/+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ MQTTVec_t mqttVec;
- /* Edge case where topic filter starts with '+' and topic name starts with '$'. */
- pTopicName = "$/test/match";
- pTopicFilter = "+/test/match";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ mqttVec.pVector = pTransportArray;
+ mqttVec.vectorLen = 10;
- /* Topic name matches all characters with topic filter, but topic filter is invalid. */
- pTopicName = "test/match/level";
- pTopicFilter = "test/match/level+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ size_t ret;
- /* Invalid topic filter where non-starting '+' is not placed after '/'.*/
- pTopicName = "test/match/level1";
- pTopicFilter = "test/match/level+";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ MQTTStatus_t status = MQTT_GetBytesInMQTTVec( &mqttVec, &ret );
- /* Invalid topic filter where intermediate '+' is not followed by '/'.*/
- pTopicName = "test/match/level";
- pTopicFilter = "test/+?level";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
+ TEST_ASSERT_EQUAL( 55, ret );
}
-/**
- * @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification of all
- * cases of matching topic filters that contain the multi-level '#' wildcard.
- */
-void test_MQTT_MatchTopic_Wildcard_MultiLevel_Match_Cases( void )
+void test_MQTT_GetBytesInMQTTVec_AdditionOverflow( void )
{
- const char * pTopicName = NULL;
- const char * pTopicFilter = NULL;
- bool matchResult = false;
+ TransportOutVector_t pTransportArray[ 3 ] =
+ {
+ { .iov_base = NULL, .iov_len = SIZE_MAX / 2 },
+ { .iov_base = NULL, .iov_len = SIZE_MAX / 2 },
+ { .iov_base = NULL, .iov_len = SIZE_MAX / 2 },
+ };
- /* Match topic filter ending with '#' with a single level .*/
- pTopicName = "/test/match/level1";
- pTopicFilter = "/test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ MQTTVec_t mqttVec;
- /* Match topic filter ending with '#' with multiple levels in topic name.*/
- pTopicName = "/test/match/level1/level2/level3";
- pTopicFilter = "/test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ mqttVec.pVector = pTransportArray;
+ mqttVec.vectorLen = 3;
- pTopicName = "/test/match/level1/level2/level3";
- pTopicFilter = "/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ size_t ret;
- /* Match when topic filter is "#" */
- pTopicName = "test/match/level";
- pTopicFilter = "#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ MQTTStatus_t status = MQTT_GetBytesInMQTTVec( &mqttVec, &ret );
- /* Test for match with a topic name starting with '$' .*/
- pTopicName = "$test/match/level1";
- pTopicFilter = "$test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ TEST_ASSERT_EQUAL( MQTTBadParameter, status );
+}
+/* ========================================================================== */
- /* Match '#' with topic name ending at the parent level. */
- pTopicName = "/test/match";
- pTopicFilter = "/test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+void test_MQTT_SerializeMQTTVec( void )
+{
+ TransportOutVector_t pTransportArray[ 6 ] =
+ {
+ { .iov_base = "This ", .iov_len = strlen( "This " ) },
+ { .iov_base = "is ", .iov_len = strlen( "is " ) },
+ { .iov_base = "a ", .iov_len = strlen( "a " ) },
+ { .iov_base = "coreMQTT ", .iov_len = strlen( "coreMQTT " ) },
+ { .iov_base = "unit-test ", .iov_len = strlen( "unit-test " ) },
+ { .iov_base = "string.", .iov_len = strlen( "string." ) }
+ };
- /* Edge case where filter ending with '/#' matches topic ending with '/'. */
- pTopicName = "/test/match/";
- pTopicFilter = "/test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ uint8_t array[ 50 ] = { 0 };
+ MQTTVec_t mqttVec;
- /* Test for topic filters containing both '+' and '#' wildcard characters. */
- pTopicName = "/test/match";
- pTopicFilter = "+/test/match/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ mqttVec.pVector = pTransportArray;
+ mqttVec.vectorLen = 6;
- pTopicName = "/test/match/level";
- pTopicFilter = "+/+/+/#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( true, matchResult );
+ MQTT_SerializeMQTTVec( array, &mqttVec );
+
+ TEST_ASSERT_EQUAL_MEMORY( "This is a coreMQTT unit-test string.", array, strlen( "This is a coreMQTT unit-test string." ) );
+ TEST_ASSERT_EQUAL_MEMORY( "\0\0\0\0\0\0\0\0\0\0\0\0\0", &array[ 37 ], 13 );
+}
+
+void test_receiveFailed( void )
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+
+ transport.recv = transportRecvFailure;
+
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+
+ mqttContext.connectStatus = MQTTConnected;
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTRecvFailed, status );
+ TEST_ASSERT_EQUAL( MQTTDisconnectPending, mqttContext.connectStatus );
}
/**
- * @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification for
- * cases of where topic filter containing '#' wildcard do not match topic name.
+ * @brief Tests MQTT_Connect behavior when attempting to resend unacknowledged publishes
+ * while the connection status is set to MQTTNotConnected in context->retrieveFunction(...) This is done to cover a branch in sendBuffer(...)
*/
-void test_MQTT_MatchTopic_Wildcard_MultiLevel_No_Match_Cases( void )
+void test_ResendUnackedPublishesWithNotConnected( void )
{
- const char * pTopicName = NULL;
- const char * pTopicFilter = NULL;
- bool matchResult = false;
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ uint32_t timeout = 2;
+ bool sessionPresent = true;
+ bool sessionPresentResult;
+ MQTTStatus_t status = MQTTSuccess;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ uint16_t packetIdentifier = 1;
- /* Edge case where topic filter starts with '#' and topic name starts with '$'. */
- pTopicName = "$/test/match";
- pTopicFilter = "#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- /* Invalid topic filter where non-starting '#' is not placed after '/'.*/
- pTopicName = "test/match/level1";
- pTopicFilter = "test/match/level#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- /* Topic name matches all characters with topic filter, but topic filter is invalid. */
- pTopicName = "test/match/level";
- pTopicFilter = "test/match/level?#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ /**
+ * Test : One packet found in ack pending state, Transport Send failed and
+ * connectStatus is set to MQTTNotConnected during the retrieveFunction using a stub.
+ */
- pTopicName = "test/match/level";
- pTopicFilter = "test/match/level#";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
+ connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
+ incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
+ incomingPacket.remainingLength = 2;
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- /* Invalid topic filters that contain '#' at a non-ending position .*/
- pTopicName = "test/match/level1/level2";
- pTopicFilter = "test/match/#/level2";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ sessionPresentResult = false;
+ mqttContext.connectStatus = MQTTNotConnected;
+ mqttContext.keepAliveIntervalSec = 0;
+ mqttContext.transportInterface.send = transportSendFailure;
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializeConnAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
+ MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
+ MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
- pTopicName = "test/match/level2";
- pTopicFilter = "#/match/level2";
- TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
- strlen( pTopicName ),
- pTopicFilter,
- strlen( pTopicFilter ),
- &matchResult ) );
- TEST_ASSERT_EQUAL( false, matchResult );
+ mqttContext.retrieveFunction = retrieveFunctionNotConnected;
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, NULL, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
-/* ========================================================================== */
+void test_MQTT_Connect_MaxPacketSizeBiggerThanBuffer( void )
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ uint32_t timeout = 2;
+ bool sessionPresentResult;
+ MQTTStatus_t status = MQTTSuccess;
+ MQTTPropBuilder_t PropertyBuilder;
+ uint32_t receiveMax = UINT32_MAX;
+
+ MQTT_ValidateConnectProperties_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ValidateConnectProperties_ReturnThruPtr_pPacketSizeMaxValue( &receiveMax );
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult, &PropertyBuilder, NULL );
+ TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+}
/**
- * @brief Tests that MQTT_GetSubAckStatusCodes works as expected in parsing the
- * payload information of a SUBACK packet.
+ * @brief Tests MQTT_ProcessLoop behavior when the event callback fails while receiving a PUBREC packet.
*/
-void test_MQTT_GetSubAckStatusCodes( void )
+void test_eventCallbackFailed( void )
{
- MQTTPacketInfo_t mqttPacketInfo = { 0 };
- size_t payloadSize;
- uint8_t * pPayloadStart;
- MQTTStatus_t status = MQTTSuccess;
- uint8_t buffer[ 10 ] = { 0 };
-
- buffer[ 0 ] = 0;
- buffer[ 1 ] = 1;
- buffer[ 2 ] = 0x00;
- buffer[ 3 ] = 0x01;
- buffer[ 4 ] = 0x02;
- buffer[ 5 ] = 0x80;
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
- /* Process a valid SUBACK packet containing whole range of server response codes. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
- mqttPacketInfo.pRemainingData = buffer;
- mqttPacketInfo.remainingLength = 6;
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
- TEST_ASSERT_EQUAL_PTR( &buffer[ 2 ], pPayloadStart );
- TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos0, pPayloadStart[ 0 ] );
- TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos1, pPayloadStart[ 1 ] );
- TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos2, pPayloadStart[ 2 ] );
- TEST_ASSERT_EQUAL_INT( MQTTSubAckFailure, pPayloadStart[ 3 ] );
- TEST_ASSERT_EQUAL_INT( 4, payloadSize );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- /* Packet is NULL. */
- status = MQTT_GetSubAckStatusCodes( NULL, &pPayloadStart, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackFail, &networkBuffer );
- /* Output parameter, pPayloadStart, is NULL. */
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, NULL, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ mqttContext.connectStatus = MQTTConnected;
- /* Output parameter, pPayloadSize, is NULL. */
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, NULL );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
+ expectParams.incomingPublish = false;
+ expectParams.updateStateStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTSuccess;
+ expectParams.stateAfterDeserialize = MQTTPubRelSend;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBREC;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- /* Remaining Data is NULL. */
- mqttPacketInfo.pRemainingData = NULL;
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
- /* non-SUBACK packet type. */
- mqttPacketInfo.type = MQTT_PACKET_TYPE_CONNACK;
- mqttPacketInfo.pRemainingData = buffer;
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- /* Invalid remaining length value in packet. */
- mqttPacketInfo.remainingLength = 0;
- mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
- status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
- TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
+ MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
+ MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, status );
}
-/* ========================================================================== */
-
/**
- * @brief Test MQTT_Status_strerror returns correct strings.
+ * @brief Tests MQTT_ProcessLoop behavior when the event callback fails while receiving a PUBLISH packet.
*/
-void test_MQTT_Status_strerror( void )
+void test_eventCallbackFailed1( void )
{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
MQTTStatus_t status;
- const char * str = NULL;
-
- status = MQTTSuccess;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTSuccess", str );
-
- status = MQTTBadParameter;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTBadParameter", str );
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
- status = MQTTNoMemory;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTNoMemory", str );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- status = MQTTSendFailed;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTSendFailed", str );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackFail, &networkBuffer );
- status = MQTTRecvFailed;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTRecvFailed", str );
+ mqttContext.connectStatus = MQTTConnected;
- status = MQTTBadResponse;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTBadResponse", str );
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
+ expectParams.incomingPublish = false;
+ expectParams.updateStateStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTSuccess;
+ expectParams.stateAfterDeserialize = MQTTPubAckSend;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- status = MQTTServerRefused;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTServerRefused", str );
- status = MQTTNoDataAvailable;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTNoDataAvailable", str );
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
- status = MQTTIllegalState;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTIllegalState", str );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, status );
+}
- status = MQTTStateCollision;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTStateCollision", str );
+/**
+ * @brief Tests MQTT_ProcessLoop behavior when the event callback returns a buffer which is
+ * bigger in size than what is allowed.
+ */
+void test_eventCallbackFailed_HugeBuffer( void )
+{
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ ProcessLoopReturns_t expectParams = { 0 };
+ MQTTPublishInfo_t publishInfo = { 0 };
- status = MQTTKeepAliveTimeout;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTKeepAliveTimeout", str );
+ publishInfo.qos = MQTTQoS1;
+ static MQTTPubAckInfo_t incomingRecords[ 10 ] = { 0 };
+ static MQTTPubAckInfo_t outgoingRecords[ 10 ] = { 0 };
- status = MQTTNeedMoreBytes;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTNeedMoreBytes", str );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- status = MQTTStatusConnected;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTStatusConnected", str );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackRetHugeBuffer, &networkBuffer );
+
+ MQTTPropBuilder_t ackPropsBuffer;
+ setupackPropsBuilder( &ackPropsBuffer );
+ mqttContext.ackPropsBuffer = ackPropsBuffer;
+ status = MQTT_InitStatefulQoS( &mqttContext,
+ outgoingRecords,
+ 10,
+ incomingRecords,
+ 10, NULL, 0 );
+ TEST_ASSERT_EQUAL( MQTTSuccess, status );
- status = MQTTStatusNotConnected;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTStatusNotConnected", str );
+ mqttContext.connectStatus = MQTTConnected;
- status = MQTTStatusDisconnectPending;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTStatusDisconnectPending", str );
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
+ expectParams.incomingPublish = false;
+ expectParams.updateStateStatus = MQTTSuccess;
+ expectParams.processLoopStatus = MQTTSuccess;
+ expectParams.stateAfterDeserialize = MQTTPubAckSend;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- status = MQTTPublishStoreFailed;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTPublishStoreFailed", str );
- status = MQTTPublishRetrieveFailed;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "MQTTPublishRetrieveFailed", str );
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
- status = MQTTPublishRetrieveFailed + 1;
- str = MQTT_Status_strerror( status );
- TEST_ASSERT_EQUAL_STRING( "Invalid MQTT Status code", str );
+ MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
+ MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTSendFailed, status );
}
-/* ========================================================================== */
-void test_MQTT_GetPacketId_NULL_Context( void )
+/**
+ * @brief Tests MQTT_ProcessLoop behavior when the event callback fails while receiving a SUBACK packet.
+ */
+void test_eventCallbackFailed2( void )
{
- uint16_t packetId = 0U;
+ MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
- packetId = MQTT_GetPacketId( NULL );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- TEST_ASSERT_EQUAL( 0, packetId );
-}
-/* ========================================================================== */
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackFail, &networkBuffer );
-void test_MQTT_GetPacketId_happy_path( void )
-{
- uint16_t packetId = 0U;
- MQTTContext_t mqttContext = { 0 };
+ mqttContext.connectStatus = MQTTConnected;
- mqttContext.nextPacketId = 5;
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_SUBACK;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- packetId = MQTT_GetPacketId( &mqttContext );
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
- TEST_ASSERT_EQUAL( 5, packetId );
- TEST_ASSERT_EQUAL( 6, mqttContext.nextPacketId );
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, status );
}
-/* ========================================================================== */
-void test_MQTT_GetPacketId_happy_path_uint16_max( void )
+/**
+ * @brief Tests MQTT_ProcessLoop behavior when the event callback fails while receiving a DISCONNECT packet.
+ */
+void test_eventCallbackFailed3( void )
{
- uint16_t packetId = 0U;
MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
- mqttContext.nextPacketId = UINT16_MAX;
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- packetId = MQTT_GetPacketId( &mqttContext );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackFail, &networkBuffer );
- TEST_ASSERT_EQUAL( UINT16_MAX, packetId );
- TEST_ASSERT_EQUAL( 1, mqttContext.nextPacketId );
-}
-/* ========================================================================== */
+ mqttContext.connectStatus = MQTTConnected;
-void test_MQTT_CancelCallback_null_context( void )
-{
- uint16_t packetId = 0U;
- MQTTStatus_t mqttStatus;
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_DISCONNECT;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- mqttStatus = MQTT_CancelCallback( NULL, packetId );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ status = MQTT_ProcessLoop( &mqttContext );
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, status );
}
-/* ========================================================================== */
-void test_MQTT_CancelCallback_null_outgoingPublishRecords( void )
+/**
+ * @brief Tests MQTT_ReceiveLoop behavior when the event callback fails while receiving a PINGRESP packet.
+ */
+void test_MQTT_ReceiveLoop_KeepAliveCallbackFail( void )
{
- uint16_t packetId = 0U;
+ MQTTContext_t context = { 0 };
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ MQTTPacketInfo_t incomingPacket = { 0 };
MQTTStatus_t mqttStatus;
- MQTTContext_t mqttContext = { 0 };
- mqttContext.outgoingPublishRecords = NULL;
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallbackFail, &networkBuffer );
+ TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
- mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
+ context.networkBuffer.size = MQTT_TEST_BUFFER_LENGTH;
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ incomingPacket.type = MQTT_PACKET_TYPE_PINGRESP;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
+
+ MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+
+ MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+
+ mqttStatus = MQTT_ReceiveLoop( &context );
+
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, mqttStatus );
}
-/* ========================================================================== */
-void test_MQTT_CancelCallback_happy_path( void )
+/**
+ * @brief Tests MQTT_Connect behavior when the event callback fails while receiving a CONNACK packet.
+ */
+void test_eventCallbackFailed4( void )
{
- uint16_t packetId = 0U;
- MQTTStatus_t mqttStatus;
MQTTContext_t mqttContext = { 0 };
+ MQTTConnectInfo_t connectInfo = { 0 };
+ MQTTStatus_t status;
+ TransportInterface_t transport = { 0 };
+ MQTTFixedBuffer_t networkBuffer = { 0 };
+ uint32_t packetSize;
+ uint32_t remainingLength;
- mqttContext.outgoingPublishRecords = NULL;
- setUPContext( &mqttContext );
+ setupTransportInterface( &transport );
+ setupNetworkBuffer( &networkBuffer );
- MQTT_RemoveStateRecord_ExpectAndReturn( &mqttContext, packetId, MQTTSuccess );
+ memset( &mqttContext, 0x0, sizeof( mqttContext ) );
+ memset( &connectInfo, 0x00, sizeof( connectInfo ) );
+ MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_Init( &mqttContext, &transport, getTime, eventCallbackFail, &networkBuffer );
- mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
+ mqttContext.connectStatus = MQTTNotConnected;
- TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
-}
-/* ========================================================================== */
+ serializeConnectFixedHeader_Stub( serializeConnectFixedHeader_cb );
+ MQTTPropAdd_MaxPacketSize_IgnoreAndReturn( MQTTSuccess );
+ MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
+ MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
+ MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
+ MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
-void test_MQTT_InitStatefulQoS_fail_null_context( void )
-{
- MQTTStatus_t mqttStatus;
- MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
- MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+ encodeVariableLength_Stub( encodeVariableLength_cb_1bytelength );
- mqttStatus = MQTT_InitStatefulQoS( NULL,
- pOutgoingPublishRecords,
- 10,
- pIncomingPublishRecords,
- 10 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
-/* ========================================================================== */
+ mqttContext.waitingForPingResp = false;
+ mqttContext.keepAliveIntervalSec = 0;
-void test_MQTT_InitStatefulQoS_zero_outgoing_size( void )
-{
- MQTTStatus_t mqttStatus;
- MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
- MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+ /* Set expected return values in the loop. All success. */
+ MQTTPacketInfo_t incomingPacket = { 0 };
+ /* Modify incoming packet depending on type to be tested. */
+ incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
+ incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
+ incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
- MQTTContext_t mqttContext = { 0 };
- mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
- pOutgoingPublishRecords,
- 0,
- pIncomingPublishRecords,
- 10 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
+ MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
+ MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
+ MQTT_DeserializeConnAck_ExpectAnyArgsAndReturn( MQTTSuccess );
+ bool sessionPresent = false;
+
+ status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0, &sessionPresent, NULL, NULL );
+ TEST_ASSERT_EQUAL( MQTTEventCallbackFailed, status );
}
-/* ========================================================================== */
-void test_MQTT_InitStatefulQoS_zero_incoming_size( void )
+
+void test_MQTT_GetPacketTypeString( void )
{
- MQTTStatus_t mqttStatus;
- MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
- MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+ const char * retval;
- MQTTContext_t mqttContext = { 0 };
+ /* Test PUBLISH packet type (special case - checks upper nibble only) */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBLISH );
+ TEST_ASSERT_EQUAL_STRING( "PUBLISH", retval );
- mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
- pOutgoingPublishRecords,
- 10,
- pIncomingPublishRecords,
- 0 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
-/* ========================================================================== */
+ /* Test PUBLISH with flags in lower nibble (DUP, QoS, RETAIN) */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBLISH | 0x01 );
+ TEST_ASSERT_EQUAL_STRING( "PUBLISH", retval );
-void test_MQTT_InitStatefulQoS_callback_is_null( void )
-{
- MQTTStatus_t mqttStatus;
- MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
- MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBLISH | 0x0F );
+ TEST_ASSERT_EQUAL_STRING( "PUBLISH", retval );
- MQTTContext_t mqttContext = { 0 };
+ /* Test CONNECT packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_CONNECT );
+ TEST_ASSERT_EQUAL_STRING( "CONNECT", retval );
- mqttContext.appCallback = NULL;
+ /* Test CONNACK packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_CONNACK );
+ TEST_ASSERT_EQUAL_STRING( "CONNACK", retval );
- mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
- pOutgoingPublishRecords,
- 10,
- pIncomingPublishRecords,
- 10 );
- TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
-}
-/* ========================================================================== */
+ /* Test PUBACK packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBACK );
+ TEST_ASSERT_EQUAL_STRING( "PUBACK", retval );
-void test_MQTT_GetBytesInMQTTVec( void )
-{
- TransportOutVector_t pTransportArray[ 10 ] =
- {
- { .iov_base = NULL, .iov_len = 1 },
- { .iov_base = NULL, .iov_len = 2 },
- { .iov_base = NULL, .iov_len = 3 },
- { .iov_base = NULL, .iov_len = 4 },
- { .iov_base = NULL, .iov_len = 5 },
- { .iov_base = NULL, .iov_len = 6 },
- { .iov_base = NULL, .iov_len = 7 },
- { .iov_base = NULL, .iov_len = 8 },
- { .iov_base = NULL, .iov_len = 9 },
- { .iov_base = NULL, .iov_len = 10 },
- };
+ /* Test PUBREC packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBREC );
+ TEST_ASSERT_EQUAL_STRING( "PUBREC", retval );
- MQTTVec_t mqttVec;
+ /* Test PUBREL packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBREL );
+ TEST_ASSERT_EQUAL_STRING( "PUBREL", retval );
- mqttVec.pVector = pTransportArray;
- mqttVec.vectorLen = 10;
+ /* Test PUBCOMP packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PUBCOMP );
+ TEST_ASSERT_EQUAL_STRING( "PUBCOMP", retval );
- size_t ret = MQTT_GetBytesInMQTTVec( &mqttVec );
+ /* Test SUBSCRIBE packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_SUBSCRIBE );
+ TEST_ASSERT_EQUAL_STRING( "SUBSCRIBE", retval );
- TEST_ASSERT_EQUAL( 55, ret );
-}
-/* ========================================================================== */
+ /* Test SUBACK packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_SUBACK );
+ TEST_ASSERT_EQUAL_STRING( "SUBACK", retval );
-void test_MQTT_SerializeMQTTVec( void )
-{
- TransportOutVector_t pTransportArray[ 6 ] =
- {
- { .iov_base = "This ", .iov_len = strlen( "This " ) },
- { .iov_base = "is ", .iov_len = strlen( "is " ) },
- { .iov_base = "a ", .iov_len = strlen( "a " ) },
- { .iov_base = "coreMQTT ", .iov_len = strlen( "coreMQTT " ) },
- { .iov_base = "unit-test ", .iov_len = strlen( "unit-test " ) },
- { .iov_base = "string.", .iov_len = strlen( "string." ) }
- };
+ /* Test UNSUBSCRIBE packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_UNSUBSCRIBE );
+ TEST_ASSERT_EQUAL_STRING( "UNSUBSCRIBE", retval );
- uint8_t array[ 50 ] = { 0 };
- MQTTVec_t mqttVec;
+ /* Test UNSUBACK packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_UNSUBACK );
+ TEST_ASSERT_EQUAL_STRING( "UNSUBACK", retval );
- mqttVec.pVector = pTransportArray;
- mqttVec.vectorLen = 6;
+ /* Test PINGREQ packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PINGREQ );
+ TEST_ASSERT_EQUAL_STRING( "PINGREQ", retval );
- MQTT_SerializeMQTTVec( array, &mqttVec );
+ /* Test PINGRESP packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_PINGRESP );
+ TEST_ASSERT_EQUAL_STRING( "PINGRESP", retval );
- TEST_ASSERT_EQUAL_MEMORY( "This is a coreMQTT unit-test string.", array, strlen( "This is a coreMQTT unit-test string." ) );
- TEST_ASSERT_EQUAL_MEMORY( "\0\0\0\0\0\0\0\0\0\0\0\0\0", &array[ 37 ], 13 );
+ /* Test DISCONNECT packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_DISCONNECT );
+ TEST_ASSERT_EQUAL_STRING( "DISCONNECT", retval );
+
+ /* Test AUTH packet type */
+ retval = MQTT_GetPacketTypeString( MQTT_PACKET_TYPE_AUTH );
+ TEST_ASSERT_EQUAL_STRING( "AUTH", retval );
+
+ /* Test unknown/invalid packet type */
+ retval = MQTT_GetPacketTypeString( 0x00 );
+ TEST_ASSERT_EQUAL_STRING( "UNKNOWN", retval );
+
+ retval = MQTT_GetPacketTypeString( 0xFF );
+ TEST_ASSERT_EQUAL_STRING( "UNKNOWN", retval );
}
diff --git a/tools/cmock/create_test.cmake b/tools/cmock/create_test.cmake
index 78b08b495..a2839e15c 100644
--- a/tools/cmock/create_test.cmake
+++ b/tools/cmock/create_test.cmake
@@ -157,7 +157,7 @@ function(create_real_library target
${real_include_list}
)
set_target_properties(${target} PROPERTIES
- COMPILE_FLAGS "-Wextra -Wpedantic \
+ COMPILE_FLAGS "-Wall -Werror -Wunused-macros -Wextra -Wpedantic \
-fprofile-arcs -ftest-coverage -fprofile-generate \
-Wno-unused-but-set-variable"
LINK_FLAGS "-fprofile-arcs -ftest-coverage \