| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706 |
- /*
- * coreMQTT <DEVELOPMENT BRANCH>
- * 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.c
- * @brief Implements the user-facing functions in core_mqtt_serializer.h.
- */
- #include <string.h>
- #include <assert.h>
- #include "core_mqtt_serializer.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.
- */
- #define MQTT_PUBLISH_FLAG_RETAIN ( 0 ) /**< @brief MQTT PUBLISH retain flag. */
- #define MQTT_PUBLISH_FLAG_QOS1 ( 1 ) /**< @brief MQTT PUBLISH QoS1 flag. */
- #define MQTT_PUBLISH_FLAG_QOS2 ( 2 ) /**< @brief MQTT PUBLISH QoS2 flag. */
- #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.
- */
- #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.
- */
- #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.
- */
- #define MQTT_REMAINING_LENGTH_INVALID ( ( size_t ) 268435456 )
- /**
- * @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 MQTT Subscription packet types.
- */
- typedef enum MQTTSubscriptionType
- {
- MQTT_SUBSCRIBE, /**< @brief The type is a SUBSCRIBE packet. */
- MQTT_UNSUBSCRIBE /**< @brief The type is a UNSUBSCRIBE packet. */
- } MQTTSubscriptionType_t;
- /*-----------------------------------------------------------*/
- /**
- * @brief Serializes MQTT PUBLISH packet into the buffer provided.
- *
- * This function serializes MQTT PUBLISH packet into #MQTTFixedBuffer_t.pBuffer.
- * 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
- * serialized.
- * @brief 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,
- uint16_t packetIdentifier,
- const MQTTFixedBuffer_t * pFixedBuffer,
- bool serializePayload );
- /**
- * @brief Calculates the packet size and remaining length of an MQTT
- * PUBLISH packet.
- *
- * @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.
- *
- * @return false if the packet would exceed the size allowed by the
- * MQTT spec; true otherwise.
- */
- static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize );
- /**
- * @brief Calculates the packet size and remaining length of an MQTT
- * SUBSCRIBE or UNSUBSCRIBE packet.
- *
- * @param[in] pSubscriptionList List of MQTT subscription info.
- * @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.
- *
- * #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,
- MQTTSubscriptionType_t subscriptionType );
- /**
- * @brief Validates parameters of #MQTT_SerializeSubscribe or
- * #MQTT_SerializeUnsubscribe.
- *
- * @param[in] pSubscriptionList List of MQTT subscription info.
- * @param[in] subscriptionCount The number of elements in pSubscriptionList.
- * @param[in] packetId Packet identifier.
- * @param[in] remainingLength Remaining length of the packet.
- * @param[in] pFixedBuffer Buffer for packet serialization.
- *
- * @return #MQTTNoMemory if pBuffer is too small to hold the MQTT packet;
- * #MQTTBadParameter if invalid parameters are passed;
- * #MQTTSuccess otherwise.
- */
- static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer );
- /**
- * @brief Serialize an MQTT CONNECT packet in the given buffer.
- *
- * @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[out] pFixedBuffer Buffer for packet serialization.
- */
- static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer );
- /**
- * @brief Prints the appropriate message for the CONNACK response code if logs
- * are enabled.
- *
- * @param[in] responseCode MQTT standard CONNACK response code.
- */
- 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.
- *
- * @param[in] length The remaining length to be encoded.
- *
- * @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 );
- /**
- * @brief Retrieves and decodes the Remaining Length from the network interface
- * by reading a single byte at a time.
- *
- * @param[in] recvFunc Network interface receive function.
- * @param[in] pNetworkContext Network interface context to the receive function.
- *
- * @return The Remaining Length of the incoming packet.
- */
- static size_t getRemainingLength( TransportRecv_t recvFunc,
- NetworkContext_t * pNetworkContext );
- /**
- * @brief Retrieves, decodes and stores the Remaining Length from the network
- * interface by reading a single byte at a time.
- *
- * @param[in] pBuffer The buffer holding the raw data to be processed
- * @param[in] pIndex Pointer to the index within the buffer to marking the end of raw data
- * available.
- * @param[in] pIncomingPacket Structure used to hold the fields of the
- * incoming packet.
- *
- * @return MQTTNeedMoreBytes is returned to show that the incoming
- * packet is not yet fully received and decoded. Otherwise, MQTTSuccess
- * shows that processing of the packet was successful.
- */
- static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
- const size_t * pIndex,
- MQTTPacketInfo_t * pIncomingPacket );
- /**
- * @brief Check if an incoming packet type is valid.
- *
- * @param[in] packetType The packet type to check.
- *
- * @return `true` if the packet type is valid; `false` otherwise.
- */
- static bool incomingPacketValid( uint8_t packetType );
- /**
- * @brief Check the remaining length of an incoming PUBLISH packet against some
- * value for QoS 0, or for QoS 1 and 2.
- *
- * The remaining length for a QoS 1 and 2 packet will always be two greater than
- * for a QoS 0.
- *
- * @param[in] remainingLength Remaining length of the PUBLISH packet.
- * @param[in] qos The QoS of the PUBLISH.
- * @param[in] qos0Minimum Minimum possible remaining length for a QoS 0 PUBLISH.
- *
- * @return #MQTTSuccess or #MQTTBadResponse.
- */
- static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
- MQTTQoS_t qos,
- size_t qos0Minimum );
- /**
- * @brief Process the flags of an incoming PUBLISH packet.
- *
- * @param[in] publishFlags Flags of an incoming PUBLISH.
- * @param[in, out] pPublishInfo Pointer to #MQTTPublishInfo_t struct where
- * output will be written.
- *
- * @return #MQTTSuccess or #MQTTBadResponse.
- */
- 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.
- *
- * @param[in] pConnack Pointer to an MQTT packet struct representing a
- * CONNACK.
- * @param[out] pSessionPresent Whether a previous session was present.
- *
- * @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.
- */
- static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
- bool * pSessionPresent );
- /**
- * @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.
- *
- * @return #MQTTSuccess, #MQTTServerRefused, or #MQTTBadResponse.
- */
- static MQTTStatus_t readSubackStatus( size_t statusCount,
- const uint8_t * pStatusStart );
- /**
- * @brief Deserialize a SUBACK packet.
- *
- * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
- * the packet identifier.
- *
- * @param[in] pSuback Pointer to an MQTT packet struct representing a SUBACK.
- * @param[out] pPacketIdentifier Packet ID of the SUBACK.
- *
- * @return #MQTTSuccess if SUBACK is valid; #MQTTBadResponse if SUBACK packet
- * doesn't follow the MQTT spec.
- */
- static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
- uint16_t * pPacketIdentifier );
- /**
- * @brief Deserialize a PUBLISH packet received from the server.
- *
- * Converts the packet from a stream of bytes to an #MQTTPublishInfo_t and
- * extracts the packet identifier. Also prints out debug log messages about the
- * packet.
- *
- * @param[in] pIncomingPacket Pointer to an MQTT packet struct representing a
- * PUBLISH.
- * @param[out] pPacketId Packet identifier of the PUBLISH.
- * @param[out] pPublishInfo Pointer to #MQTTPublishInfo_t where output is
- * written.
- *
- * @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 );
- /**
- * @brief Deserialize an UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP packet.
- *
- * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
- * the packet identifier.
- *
- * @param[in] pAck Pointer to the MQTT packet structure representing the packet.
- * @param[out] pPacketIdentifier Packet ID of the ack type packet.
- *
- * @return #MQTTSuccess if UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP is valid;
- * #MQTTBadResponse if the packet doesn't follow the MQTT spec.
- */
- static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
- uint16_t * pPacketIdentifier );
- /**
- * @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 );
- /*-----------------------------------------------------------*/
- static size_t remainingLengthEncodedSize( 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;
- }
- LogDebug( ( "Encoded size for length %lu is %lu bytes.",
- ( unsigned long ) length,
- ( unsigned long ) encodedSize ) );
- return encodedSize;
- }
- /*-----------------------------------------------------------*/
- 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 )
- {
- bool status = true;
- size_t packetSize = 0, payloadLimit = 0;
- assert( pPublishInfo != NULL );
- assert( pRemainingLength != NULL );
- assert( pPacketSize != NULL );
- /* 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.
- */
- packetSize += pPublishInfo->topicNameLength + sizeof( uint16_t );
- /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte
- * packet identifier. */
- if( pPublishInfo->qos > MQTTQoS0 )
- {
- 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;
- /* Ensure that the given payload fits within the calculated limit. */
- if( pPublishInfo->payloadLength > payloadLimit )
- {
- LogError( ( "PUBLISH payload 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,
- MQTT_MAX_REMAINING_LENGTH ) );
- status = false;
- }
- 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 );
- /* Check that the given payload fits within the size allowed by MQTT spec. */
- if( pPublishInfo->payloadLength > payloadLimit )
- {
- LogError( ( "PUBLISH payload 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,
- MQTT_MAX_REMAINING_LENGTH ) );
- status = false;
- }
- else
- {
- /* Set the "Remaining length" output parameter and calculate the full
- * size of the PUBLISH packet. */
- *pRemainingLength = packetSize;
- packetSize += 1U + remainingLengthEncodedSize( packetSize );
- *pPacketSize = packetSize;
- }
- }
- 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,
- uint8_t * pBuffer,
- size_t * headerSize )
- {
- size_t headerLength;
- uint8_t * pIndex;
- MQTTStatus_t status = MQTTSuccess;
- /* 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 )
- {
- 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 */
- }
- if( pPublishInfo->retain == true )
- {
- LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
- }
- if( pPublishInfo->dup == true )
- {
- LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
- }
- *pIndex = publishFlags;
- pIndex++;
- /* The "Remaining length" is encoded from the second byte. */
- pIndex = encodeRemainingLength( 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;
- }
- /*-----------------------------------------------------------*/
- static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
- size_t remainingLength,
- uint16_t packetIdentifier,
- const MQTTFixedBuffer_t * pFixedBuffer,
- bool serializePayload )
- {
- uint8_t * pIndex = NULL;
- /* The first byte of a PUBLISH packet contains the packet type and flags. */
- uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
- assert( pPublishInfo != NULL );
- assert( pFixedBuffer != NULL );
- assert( pFixedBuffer->pBuffer != NULL );
- /* Packet Id should be non zero for Qos 1 and Qos 2. */
- 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 ) );
- /* Get the start address of the buffer. */
- pIndex = pFixedBuffer->pBuffer;
- 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 */
- }
- if( pPublishInfo->retain == true )
- {
- LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
- }
- if( pPublishInfo->dup == true )
- {
- LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
- }
- *pIndex = publishFlags;
- pIndex++;
- /* The "Remaining length" is encoded from the second byte. */
- pIndex = encodeRemainingLength( pIndex, remainingLength );
- /* The topic name is placed after the "Remaining length". */
- pIndex = encodeString( pIndex,
- pPublishInfo->pTopicName,
- pPublishInfo->topicNameLength );
- /* A packet identifier is required for QoS 1 and 2 messages. */
- if( pPublishInfo->qos > MQTTQoS0 )
- {
- LogDebug( ( "Adding packet Id in PUBLISH packet." ) );
- /* Place the packet identifier into the PUBLISH packet. */
- *pIndex = UINT16_HIGH_BYTE( packetIdentifier );
- pIndex[ 1U ] = UINT16_LOW_BYTE( packetIdentifier );
- pIndex = &pIndex[ 2U ];
- }
- /* The payload is placed after the packet identifier.
- * Payload is copied over only if required by the flag serializePayload.
- * This will help reduce an unnecessary copy of the payload into the buffer.
- */
- if( ( pPublishInfo->payloadLength > 0U ) &&
- ( serializePayload == true ) )
- {
- LogDebug( ( "Copying PUBLISH payload of length =%lu to buffer",
- ( unsigned long ) pPublishInfo->payloadLength ) );
- ( void ) memcpy( ( void * ) pIndex, ( const void * ) pPublishInfo->pPayload, pPublishInfo->payloadLength );
- /* Move the index to after the payload. */
- pIndex = &pIndex[ pPublishInfo->payloadLength ];
- }
- /* Ensure that the difference between the end and beginning of the buffer
- * is less than the buffer size. */
- assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
- }
- static size_t getRemainingLength( TransportRecv_t recvFunc,
- NetworkContext_t * pNetworkContext )
- {
- size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
- uint8_t encodedByte = 0;
- int32_t bytesReceived = 0;
- /* This algorithm is copied from the MQTT v3.1.1 spec. */
- do
- {
- if( multiplier > 2097152U ) /* 128 ^ 3 */
- {
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;
- }
- else
- {
- bytesReceived = recvFunc( pNetworkContext, &encodedByte, 1U );
- if( bytesReceived == 1 )
- {
- remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
- multiplier *= 128U;
- bytesDecoded++;
- }
- else
- {
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;
- }
- }
- if( remainingLength == MQTT_REMAINING_LENGTH_INVALID )
- {
- break;
- }
- } while( ( encodedByte & 0x80U ) != 0U );
- /* Check that the decoded remaining length conforms to the MQTT specification. */
- if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )
- {
- expectedSize = remainingLengthEncodedSize( remainingLength );
- if( bytesDecoded != expectedSize )
- {
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;
- }
- }
- return remainingLength;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
- const size_t * pIndex,
- MQTTPacketInfo_t * pIncomingPacket )
- {
- size_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. */
- do
- {
- if( multiplier > 2097152U ) /* 128 ^ 3 */
- {
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;
- LogError( ( "Invalid remaining length in the packet.\n" ) );
- status = MQTTBadResponse;
- }
- else
- {
- if( *pIndex > ( bytesDecoded + 1U ) )
- {
- /* Get the next byte. It is at the next position after the bytes
- * decoded till now since the header of one byte was read before. */
- encodedByte = pBuffer[ bytesDecoded + 1U ];
- remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
- multiplier *= 128U;
- bytesDecoded++;
- }
- else
- {
- status = MQTTNeedMoreBytes;
- }
- }
- /* If the response is incorrect, or no more data is available, then
- * break out of the loop. */
- if( ( remainingLength == MQTT_REMAINING_LENGTH_INVALID ) ||
- ( status != MQTTSuccess ) )
- {
- break;
- }
- } while( ( encodedByte & 0x80U ) != 0U );
- if( status == MQTTSuccess )
- {
- /* Check that the decoded remaining length conforms to the MQTT specification. */
- expectedSize = remainingLengthEncodedSize( remainingLength );
- if( bytesDecoded != expectedSize )
- {
- LogError( ( "Expected and actual length of decoded bytes do not match.\n" ) );
- status = MQTTBadResponse;
- }
- else
- {
- pIncomingPacket->remainingLength = remainingLength;
- pIncomingPacket->headerLength = bytesDecoded + 1U;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static bool incomingPacketValid( uint8_t packetType )
- {
- bool status = false;
- /* Check packet type. Mask out lower bits to ignore flags. */
- switch( packetType & 0xF0U )
- {
- /* Valid incoming packet types. */
- case MQTT_PACKET_TYPE_CONNACK:
- case MQTT_PACKET_TYPE_PUBLISH:
- case MQTT_PACKET_TYPE_PUBACK:
- case MQTT_PACKET_TYPE_PUBREC:
- case MQTT_PACKET_TYPE_PUBCOMP:
- case MQTT_PACKET_TYPE_SUBACK:
- case MQTT_PACKET_TYPE_UNSUBACK:
- case MQTT_PACKET_TYPE_PINGRESP:
- status = true;
- break;
- case ( MQTT_PACKET_TYPE_PUBREL & 0xF0U ):
- /* The second bit of a PUBREL must be set. */
- if( ( packetType & 0x02U ) > 0U )
- {
- status = true;
- }
- break;
- /* Any other packet type is invalid. */
- default:
- LogWarn( ( "Incoming packet invalid: Packet type=%u.",
- ( unsigned int ) packetType ) );
- break;
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
- MQTTQoS_t qos,
- size_t qos0Minimum )
- {
- MQTTStatus_t status = MQTTSuccess;
- /* Sanity checks for "Remaining length". */
- if( qos == MQTTQoS0 )
- {
- /* Check that the "Remaining length" is greater than the minimum. */
- if( remainingLength < qos0Minimum )
- {
- LogError( ( "QoS 0 PUBLISH cannot have a remaining length less than %lu.",
- ( unsigned long ) qos0Minimum ) );
- status = MQTTBadResponse;
- }
- }
- else
- {
- /* Check that the "Remaining length" is greater than the minimum. For
- * QoS 1 or 2, this will be two bytes greater than for QoS 0 due to the
- * packet identifier. */
- if( remainingLength < ( qos0Minimum + 2U ) )
- {
- LogError( ( "QoS 1 or 2 PUBLISH cannot have a remaining length less than %lu.",
- ( unsigned long ) ( qos0Minimum + 2U ) ) );
- status = MQTTBadResponse;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
- MQTTPublishInfo_t * pPublishInfo )
- {
- MQTTStatus_t status = MQTTSuccess;
- assert( pPublishInfo != NULL );
- /* Check for QoS 2. */
- if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) )
- {
- /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */
- if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
- {
- LogError( ( "Bad QoS: 3." ) );
- status = MQTTBadResponse;
- }
- else
- {
- pPublishInfo->qos = MQTTQoS2;
- }
- }
- /* Check for QoS 1. */
- else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
- {
- pPublishInfo->qos = MQTTQoS1;
- }
- /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */
- else
- {
- pPublishInfo->qos = MQTTQoS0;
- }
- if( status == MQTTSuccess )
- {
- LogDebug( ( "QoS is %d.", ( int ) pPublishInfo->qos ) );
- /* Parse the Retain bit. */
- pPublishInfo->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
- LogDebug( ( "Retain bit is %d.", ( int ) pPublishInfo->retain ) );
- /* Parse the DUP bit. */
- pPublishInfo->dup = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
- LogDebug( ( "DUP bit is %d.", ( int ) pPublishInfo->dup ) );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static void logConnackResponse( uint8_t responseCode )
- {
- const char * const pConnackResponses[ 6 ] =
- {
- "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 */
- };
- /* Avoid unused parameter warning when assert and logs are disabled. */
- ( void ) responseCode;
- ( void ) pConnackResponses;
- assert( responseCode <= 5U );
- if( responseCode == 0u )
- {
- /* Log at Debug level for a success CONNACK response. */
- LogDebug( ( "%s", pConnackResponses[ 0 ] ) );
- }
- else
- {
- /* Log an error based on the CONNACK response code. */
- LogError( ( "%s", pConnackResponses[ responseCode ] ) );
- }
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
- bool * pSessionPresent )
- {
- MQTTStatus_t status = MQTTSuccess;
- const uint8_t * pRemainingData = NULL;
- assert( pConnack != NULL );
- assert( pSessionPresent != NULL );
- pRemainingData = pConnack->pRemainingData;
- /* 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 )
- {
- LogError( ( "CONNACK does not have remaining length of %u.",
- ( unsigned int ) MQTT_PACKET_CONNACK_REMAINING_LENGTH ) );
- 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 )
- {
- LogError( ( "Reserved bits in CONNACK incorrect." ) );
- 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 )
- {
- LogDebug( ( "CONNACK session present bit set." ) );
- *pSessionPresent = true;
- /* 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;
- }
- }
- 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 )
- {
- 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 )
- {
- status = MQTTServerRefused;
- }
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize,
- MQTTSubscriptionType_t subscriptionType )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t i = 0, packetSize = 0;
- assert( pSubscriptionList != NULL );
- assert( subscriptionCount != 0U );
- assert( pRemainingLength != NULL );
- assert( pPacketSize != NULL );
- /* The variable header of a subscription packet consists of a 2-byte packet
- * identifier. */
- 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. */
- 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 )
- {
- packetSize += 1U;
- }
- /* Validate each topic filter. */
- if( ( pSubscriptionList[ i ].topicFilterLength == 0U ) ||
- ( pSubscriptionList[ i ].pTopicFilter == NULL ) )
- {
- 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. */
- }
- }
- /* 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 )
- {
- LogError( ( "Subscription packet length of %lu exceeds"
- "the MQTT 3.1.1 maximum packet length of %lu.",
- ( unsigned long ) packetSize,
- MQTT_MAX_REMAINING_LENGTH ) );
- status = MQTTBadParameter;
- }
- if( status == MQTTSuccess )
- {
- *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. */
- *pPacketSize = packetSize;
- }
- LogDebug( ( "Subscription packet remaining length=%lu and packet size=%lu.",
- ( unsigned long ) *pRemainingLength,
- ( unsigned long ) *pPacketSize ) );
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t readSubackStatus( size_t statusCount,
- const uint8_t * pStatusStart )
- {
- MQTTStatus_t status = MQTTSuccess;
- 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.",
- ( unsigned long ) i,
- ( unsigned int ) subscriptionStatus ) );
- break;
- case 0x80:
- LogWarn( ( "Topic filter %lu refused.", ( unsigned long ) i ) );
- /* Application should remove subscription from the list */
- status = MQTTServerRefused;
- break;
- default:
- LogError( ( "Bad SUBSCRIBE status %u.",
- ( unsigned int ) subscriptionStatus ) );
- status = MQTTBadResponse;
- break;
- }
- /* Stop parsing the subscription statuses if a bad response was received. */
- if( status == MQTTBadResponse )
- {
- break;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
- uint16_t * pPacketIdentifier )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t remainingLength;
- const uint8_t * pVariableHeader = NULL;
- assert( pSuback != NULL );
- assert( pPacketIdentifier != NULL );
- remainingLength = pSuback->remainingLength;
- pVariableHeader = pSuback->pRemainingData;
- /* 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 )
- {
- LogError( ( "SUBACK cannot have a remaining length less than 3." ) );
- 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 ) );
- if( *pPacketIdentifier == 0U )
- {
- status = MQTTBadResponse;
- }
- else
- {
- status = readSubackStatus( remainingLength - sizeof( uint16_t ),
- &pVariableHeader[ sizeof( uint16_t ) ] );
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t packetSize = 0;
- /* Validate all the parameters. */
- if( ( pFixedBuffer == NULL ) || ( pSubscriptionList == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
- "pSubscriptionList=%p.",
- ( void * ) pFixedBuffer,
- ( void * ) pSubscriptionList ) );
- status = MQTTBadParameter;
- }
- /* A buffer must be configured for serialization. */
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
- status = MQTTBadParameter;
- }
- else if( subscriptionCount == 0U )
- {
- LogError( ( "Subscription count is 0." ) );
- status = MQTTBadParameter;
- }
- else if( packetId == 0U )
- {
- LogError( ( "Packet Id for subscription packet is 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* The serialized packet size = First byte
- * + length of encoded size of remaining length
- * + remaining length. */
- packetSize = 1U + remainingLengthEncodedSize( remainingLength )
- + remainingLength;
- if( packetSize > pFixedBuffer->size )
- {
- LogError( ( "Buffer size of %lu is not sufficient to hold "
- "serialized packet of size of %lu.",
- ( unsigned long ) pFixedBuffer->size,
- ( unsigned long ) packetSize ) );
- status = MQTTNoMemory;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
- uint16_t * pPacketId,
- MQTTPublishInfo_t * pPublishInfo )
- {
- MQTTStatus_t status = MQTTSuccess;
- const uint8_t * pVariableHeader, * pPacketIdentifierHigh = NULL;
- assert( pIncomingPacket != NULL );
- assert( pPacketId != NULL );
- assert( pPublishInfo != NULL );
- assert( pIncomingPacket->pRemainingData != NULL );
- pVariableHeader = 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. */
- status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
- pPublishInfo->qos,
- MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0 );
- }
- 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 );
- /* Sanity checks for topic name length and "Remaining length". The remaining
- * length must be at least as large as the variable length header. */
- status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
- pPublishInfo->qos,
- pPublishInfo->topicNameLength + sizeof( uint16_t ) );
- }
- if( status == MQTTSuccess )
- {
- /* Parse the topic. */
- pPublishInfo->pTopicName = ( const char * ) ( &pVariableHeader[ sizeof( uint16_t ) ] );
- LogDebug( ( "Topic name length: %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 ] );
- if( pPublishInfo->qos > MQTTQoS0 )
- {
- *pPacketId = UINT16_DECODE( pPacketIdentifierHigh );
- 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 )
- {
- /* 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 );
- if( pPublishInfo->qos != MQTTQoS0 )
- {
- /* Two more bytes for the packet identifier. */
- pPublishInfo->payloadLength -= sizeof( uint16_t );
- }
- /* Set payload if it exists. */
- pPublishInfo->pPayload = ( pPublishInfo->payloadLength != 0U ) ? pPacketIdentifierHigh : NULL;
- LogDebug( ( "Payload length %lu.",
- ( unsigned long ) pPublishInfo->payloadLength ) );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
- uint16_t * pPacketIdentifier )
- {
- MQTTStatus_t status = MQTTSuccess;
- assert( pAck != NULL );
- assert( pPacketIdentifier != NULL );
- /* Check that the "Remaining length" of the received ACK is 2. */
- if( pAck->remainingLength != MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH )
- {
- LogError( ( "ACK does not have remaining length of %u.",
- ( unsigned int ) MQTT_PACKET_SIMPLE_ACK_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 ) );
- /* Packet identifier cannot be 0. */
- if( *pPacketIdentifier == 0U )
- {
- LogError( ( "Packet identifier cannot be 0." ) );
- status = MQTTBadResponse;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp )
- {
- 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 )
- {
- LogError( ( "PINGRESP does not have remaining length of %u.",
- MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) );
- status = MQTTBadResponse;
- }
- return status;
- }
- 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;
- /* 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 = encodeRemainingLength( 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_3_1_1;
- 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;
- }
- /*-----------------------------------------------------------*/
- static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- uint8_t * pIndex = NULL;
- assert( pConnectInfo != NULL );
- assert( pFixedBuffer != NULL );
- assert( pFixedBuffer->pBuffer != NULL );
- pIndex = pFixedBuffer->pBuffer;
- /* Serialize the header. */
- pIndex = MQTT_SerializeConnectFixedHeader( pIndex,
- pConnectInfo,
- pWillInfo,
- remainingLength );
- /* Write the client identifier into the CONNECT packet. */
- pIndex = encodeString( pIndex,
- pConnectInfo->pClientIdentifier,
- pConnectInfo->clientIdentifierLength );
- /* Write the will topic name and message into the CONNECT packet if provided. */
- if( pWillInfo != NULL )
- {
- pIndex = encodeString( pIndex,
- pWillInfo->pTopicName,
- pWillInfo->topicNameLength );
- pIndex = encodeString( pIndex,
- pWillInfo->pPayload,
- ( uint16_t ) pWillInfo->payloadLength );
- }
- /* Encode the user name if provided. */
- if( pConnectInfo->pUserName != NULL )
- {
- pIndex = encodeString( pIndex, pConnectInfo->pUserName, pConnectInfo->userNameLength );
- }
- /* Encode the password if provided. */
- if( pConnectInfo->pPassword != NULL )
- {
- pIndex = encodeString( pIndex, pConnectInfo->pPassword, pConnectInfo->passwordLength );
- }
- LogDebug( ( "Length of serialized CONNECT packet is %lu.",
- ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
- /* Ensure that the difference between the end and beginning of the buffer
- * is less than the buffer size. */
- assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t remainingLength;
- /* 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 ) )
- {
- LogError( ( "Mqtt_GetConnectPacketSize() client identifier must be set." ) );
- status = MQTTBadParameter;
- }
- else if( ( pWillInfo != NULL ) && ( pWillInfo->payloadLength > ( size_t ) UINT16_MAX ) )
- {
- /* 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;
- }
- else
- {
- /* Add the length of the client identifier. */
- connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
- /* Add the lengths of the will message and topic name if provided. */
- if( pWillInfo != NULL )
- {
- connectPacketSize += pWillInfo->topicNameLength + sizeof( uint16_t ) +
- pWillInfo->payloadLength + sizeof( uint16_t );
- }
- /* Add the lengths of the user name and password if provided. */
- if( pConnectInfo->pUserName != NULL )
- {
- connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );
- }
- if( pConnectInfo->pPassword != NULL )
- {
- connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );
- }
- /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has
- * been calculated. */
- remainingLength = connectPacketSize;
- /* 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 */
- *pRemainingLength = remainingLength;
- *pPacketSize = connectPacketSize;
- LogDebug( ( "CONNECT packet remaining length=%lu and packet size=%lu.",
- ( unsigned long ) *pRemainingLength,
- ( unsigned long ) *pPacketSize ) );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
- const MQTTPublishInfo_t * pWillInfo,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t connectPacketSize = 0;
- /* Validate arguments. */
- if( ( pConnectInfo == NULL ) || ( pFixedBuffer == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
- "pFixedBuffer=%p.",
- ( void * ) pConnectInfo,
- ( void * ) pFixedBuffer ) );
- status = MQTTBadParameter;
- }
- /* A buffer must be configured for serialization. */
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
- status = MQTTBadParameter;
- }
- else if( ( pWillInfo != NULL ) && ( pWillInfo->pTopicName == NULL ) )
- {
- LogError( ( "pWillInfo->pTopicName cannot be NULL if Will is present." ) );
- 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;
- /* Check that the full packet size fits within the given buffer. */
- if( connectPacketSize > pFixedBuffer->size )
- {
- LogError( ( "Buffer size of %lu is not sufficient to hold "
- "serialized CONNECT packet of size of %lu.",
- ( unsigned long ) pFixedBuffer->size,
- ( unsigned long ) connectPacketSize ) );
- status = MQTTNoMemory;
- }
- else
- {
- serializeConnectPacket( pConnectInfo,
- pWillInfo,
- remainingLength,
- pFixedBuffer );
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- /* Validate parameters. */
- if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
- ( pPacketSize == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
- "pRemainingLength=%p, pPacketSize=%p.",
- ( void * ) pSubscriptionList,
- ( void * ) pRemainingLength,
- ( void * ) pPacketSize ) );
- status = MQTTBadParameter;
- }
- else if( subscriptionCount == 0U )
- {
- LogError( ( "subscriptionCount is 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* Calculate the MQTT SUBSCRIBE packet size. */
- status = calculateSubscriptionPacketSize( pSubscriptionList,
- subscriptionCount,
- pRemainingLength,
- pPacketSize,
- MQTT_SUBSCRIBE );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- 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,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- size_t i = 0;
- uint8_t * pIndex = NULL;
- /* Validate all the parameters. */
- MQTTStatus_t status =
- validateSubscriptionSerializeParams( pSubscriptionList,
- subscriptionCount,
- packetId,
- remainingLength,
- pFixedBuffer );
- if( status == MQTTSuccess )
- {
- pIndex = pFixedBuffer->pBuffer;
- pIndex = MQTT_SerializeSubscribeHeader( remainingLength,
- pIndex,
- packetId );
- /* Serialize each subscription topic filter and QoS. */
- for( i = 0; i < subscriptionCount; i++ )
- {
- pIndex = encodeString( pIndex,
- pSubscriptionList[ i ].pTopicFilter,
- pSubscriptionList[ i ].topicFilterLength );
- /* Place the QoS in the SUBSCRIBE packet. */
- *pIndex = ( uint8_t ) ( pSubscriptionList[ i ].qos );
- pIndex++;
- }
- LogDebug( ( "Length of serialized SUBSCRIBE packet is %lu.",
- ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- size_t * pRemainingLength,
- size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- /* Validate parameters. */
- if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
- ( pPacketSize == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
- "pRemainingLength=%p, pPacketSize=%p.",
- ( void * ) pSubscriptionList,
- ( void * ) pRemainingLength,
- ( void * ) pPacketSize ) );
- status = MQTTBadParameter;
- }
- else if( subscriptionCount == 0U )
- {
- LogError( ( "Subscription count is 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* Calculate the MQTT UNSUBSCRIBE packet size. */
- status = calculateSubscriptionPacketSize( pSubscriptionList,
- subscriptionCount,
- pRemainingLength,
- pPacketSize,
- MQTT_UNSUBSCRIBE );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
- size_t subscriptionCount,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t i = 0;
- uint8_t * pIndex = NULL;
- /* Validate all the parameters. */
- status = validateSubscriptionSerializeParams( pSubscriptionList,
- subscriptionCount,
- packetId,
- remainingLength,
- pFixedBuffer );
- if( status == MQTTSuccess )
- {
- /* Get the start of the buffer to the iterator variable. */
- pIndex = pFixedBuffer->pBuffer;
- pIndex = MQTT_SerializeUnsubscribeHeader( remainingLength, pIndex, packetId );
- /* Serialize each subscription topic filter. */
- for( i = 0; i < subscriptionCount; i++ )
- {
- pIndex = encodeString( pIndex,
- pSubscriptionList[ i ].pTopicFilter,
- pSubscriptionList[ i ].topicFilterLength );
- }
- LogDebug( ( "Length of serialized UNSUBSCRIBE packet is %lu.",
- ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
- size_t * pRemainingLength,
- size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pPublishInfo=%p, "
- "pRemainingLength=%p, pPacketSize=%p.",
- ( void * ) pPublishInfo,
- ( void * ) pRemainingLength,
- ( void * ) pPacketSize ) );
- 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
- {
- /* 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;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t packetSize = 0;
- if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
- "pPublishInfo=%p.",
- ( void * ) pFixedBuffer,
- ( void * ) pPublishInfo ) );
- status = MQTTBadParameter;
- }
- /* A buffer must be configured for serialization. */
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
- status = MQTTBadParameter;
- }
- /* For serializing a publish, if there exists a payload, then the buffer
- * cannot be NULL. */
- 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( ( 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( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
- {
- LogError( ( "Packet ID is 0 for PUBLISH with QoS=%u.",
- ( unsigned int ) pPublishInfo->qos ) );
- status = MQTTBadParameter;
- }
- else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
- {
- LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* Length of serialized packet = First byte
- * + Length of encoded remaining length
- * + Remaining length. */
- packetSize = 1U + remainingLengthEncodedSize( remainingLength )
- + remainingLength;
- }
- if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
- {
- LogError( ( "Buffer size of %lu is not sufficient to hold "
- "serialized PUBLISH packet of size of %lu.",
- ( unsigned long ) pFixedBuffer->size,
- ( unsigned long ) packetSize ) );
- status = MQTTNoMemory;
- }
- if( status == MQTTSuccess )
- {
- /* Serialize publish with header and payload. */
- serializePublishCommon( pPublishInfo,
- remainingLength,
- packetId,
- pFixedBuffer,
- true );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
- uint16_t packetId,
- size_t remainingLength,
- const MQTTFixedBuffer_t * pFixedBuffer,
- size_t * pHeaderSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- size_t packetSize = 0;
- if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) ||
- ( pHeaderSize == NULL ) )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
- "pPublishInfo=%p, pHeaderSize=%p.",
- ( void * ) pFixedBuffer,
- ( void * ) pPublishInfo,
- ( void * ) pHeaderSize ) );
- status = MQTTBadParameter;
- }
- /* A buffer must be configured for serialization. */
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
- 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( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
- {
- LogError( ( "Packet Id is 0 for publish with QoS=%hu.",
- ( unsigned short ) pPublishInfo->qos ) );
- status = MQTTBadParameter;
- }
- else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
- {
- LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* Length of serialized packet = First byte
- * + Length of encoded remaining length
- * + Remaining length
- * - Payload Length.
- */
- packetSize = 1U + remainingLengthEncodedSize( remainingLength )
- + remainingLength
- - pPublishInfo->payloadLength;
- }
- if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
- {
- LogError( ( "Buffer size of %lu is not sufficient to hold "
- "serialized PUBLISH header packet of size of %lu.",
- ( unsigned long ) pFixedBuffer->size,
- ( unsigned long ) ( packetSize - pPublishInfo->payloadLength ) ) );
- status = MQTTNoMemory;
- }
- if( status == MQTTSuccess )
- {
- /* Serialize publish without copying the payload. */
- serializePublishCommon( pPublishInfo,
- remainingLength,
- packetId,
- pFixedBuffer,
- false );
- /* Header size is the same as calculated packet size. */
- *pHeaderSize = packetSize;
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
- uint8_t packetType,
- uint16_t packetId )
- {
- MQTTStatus_t status = MQTTSuccess;
- if( pFixedBuffer == NULL )
- {
- LogError( ( "Provided buffer is NULL." ) );
- status = MQTTBadParameter;
- }
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
- status = MQTTBadParameter;
- }
- /* The buffer must be able to fit 4 bytes for the packet. */
- else if( pFixedBuffer->size < MQTT_PUBLISH_ACK_PACKET_SIZE )
- {
- LogError( ( "Insufficient memory for packet." ) );
- status = MQTTNoMemory;
- }
- else if( packetId == 0U )
- {
- LogError( ( "Packet ID cannot be 0." ) );
- status = MQTTBadParameter;
- }
- else
- {
- switch( packetType )
- {
- /* Only publish acks are serialized by the client. */
- case MQTT_PACKET_TYPE_PUBACK:
- case MQTT_PACKET_TYPE_PUBREC:
- case MQTT_PACKET_TYPE_PUBREL:
- case MQTT_PACKET_TYPE_PUBCOMP:
- pFixedBuffer->pBuffer[ 0 ] = packetType;
- pFixedBuffer->pBuffer[ 1 ] = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
- pFixedBuffer->pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetId );
- pFixedBuffer->pBuffer[ 3 ] = UINT16_LOW_BYTE( packetId );
- break;
- default:
- LogError( ( "Packet type is not a publish ACK: Packet type=%02x",
- ( unsigned int ) packetType ) );
- status = MQTTBadParameter;
- break;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- if( pPacketSize == NULL )
- {
- LogError( ( "pPacketSize is NULL." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* MQTT DISCONNECT packets always have the same size. */
- *pPacketSize = MQTT_DISCONNECT_PACKET_SIZE;
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
- {
- MQTTStatus_t status = MQTTSuccess;
- /* Validate arguments. */
- if( pFixedBuffer == NULL )
- {
- LogError( ( "pFixedBuffer cannot be NULL." ) );
- status = MQTTBadParameter;
- }
- else if( pFixedBuffer->pBuffer == NULL )
- {
- LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* Empty else MISRA 15.7 */
- }
- if( status == MQTTSuccess )
- {
- if( pFixedBuffer->size < MQTT_DISCONNECT_PACKET_SIZE )
- {
- 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 ) );
- status = MQTTNoMemory;
- }
- }
- if( status == MQTTSuccess )
- {
- pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
- pFixedBuffer->pBuffer[ 1 ] = MQTT_DISCONNECT_REMAINING_LENGTH;
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize )
- {
- MQTTStatus_t status = MQTTSuccess;
- if( pPacketSize == NULL )
- {
- LogError( ( "pPacketSize is NULL." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* MQTT PINGREQ packets always have the same size. */
- *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- 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
- {
- /* Empty else MISRA 15.7 */
- }
- 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 )
- {
- 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
- {
- status = deserializePublish( pIncomingPacket, pPacketId, pPublishInfo );
- }
- return status;
- }
- /*-----------------------------------------------------------*/
- MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
- uint16_t * pPacketId,
- bool * pSessionPresent )
- {
- MQTTStatus_t status = MQTTSuccess;
- if( pIncomingPacket == NULL )
- {
- LogError( ( "pIncomingPacket cannot be NULL." ) );
- 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 ) )
- {
- 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 ) &&
- ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
- {
- LogError( ( "Remaining data of incoming packet is NULL." ) );
- status = MQTTBadParameter;
- }
- else
- {
- /* 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;
- 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;
- /* Any other packet type is invalid. */
- default:
- LogError( ( "IotMqtt_DeserializeResponse() 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 )
- {
- pIncomingPacket->remainingLength = getRemainingLength( readFunc,
- pNetworkContext );
- 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
- {
- /* Empty else MISRA 15.7 */
- }
- 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 )
- {
- status = processRemainingLength( pBuffer,
- pIndex,
- pIncomingPacket );
- }
- else
- {
- LogError( ( "Incoming packet invalid: Packet type=%u.",
- ( unsigned int ) pIncomingPacket->type ) );
- status = MQTTBadResponse;
- }
- }
- return status;
- }
- /*-----------------------------------------------------------*/
|