]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h
Correct an err in queue.c introduced when previously updating behaviour when queue...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / mqtt / src / private / iot_mqtt_internal.h
1 /*\r
2  * Amazon FreeRTOS MQTT V2.0.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file iot_mqtt_internal.h\r
28  * @brief Internal header of MQTT library. This header should not be included in\r
29  * typical application code.\r
30  */\r
31 \r
32 #ifndef IOT_MQTT_INTERNAL_H_\r
33 #define IOT_MQTT_INTERNAL_H_\r
34 \r
35 /* The config header is always included first. */\r
36 #include "iot_config.h"\r
37 \r
38 /* Linear containers (lists and queues) include. */\r
39 #include "iot_linear_containers.h"\r
40 \r
41 /* MQTT include. */\r
42 #include "iot_mqtt.h"\r
43 \r
44 /* Task pool include. */\r
45 #include "iot_taskpool.h"\r
46 \r
47 /**\r
48  * @def IotMqtt_Assert( expression )\r
49  * @brief Assertion macro for the MQTT library.\r
50  *\r
51  * Set @ref IOT_MQTT_ENABLE_ASSERTS to `1` to enable assertions in the MQTT\r
52  * library.\r
53  *\r
54  * @param[in] expression Expression to be evaluated.\r
55  */\r
56 #if IOT_MQTT_ENABLE_ASSERTS == 1\r
57     #ifndef IotMqtt_Assert\r
58         #include <assert.h>\r
59         #define IotMqtt_Assert( expression )    assert( expression )\r
60     #endif\r
61 #else\r
62     #define IotMqtt_Assert( expression )\r
63 #endif\r
64 \r
65 /* Configure logs for MQTT functions. */\r
66 #ifdef IOT_LOG_LEVEL_MQTT\r
67     #define LIBRARY_LOG_LEVEL        IOT_LOG_LEVEL_MQTT\r
68 #else\r
69     #ifdef IOT_LOG_LEVEL_GLOBAL\r
70         #define LIBRARY_LOG_LEVEL    IOT_LOG_LEVEL_GLOBAL\r
71     #else\r
72         #define LIBRARY_LOG_LEVEL    IOT_LOG_NONE\r
73     #endif\r
74 #endif\r
75 \r
76 #define LIBRARY_LOG_NAME    ( "MQTT" )\r
77 #include "iot_logging_setup.h"\r
78 \r
79 /*\r
80  * Provide default values for undefined memory allocation functions based on\r
81  * the usage of dynamic memory allocation.\r
82  */\r
83 #if IOT_STATIC_MEMORY_ONLY == 1\r
84     #include "private/iot_static_memory.h"\r
85 \r
86 /**\r
87  * @brief Allocate an #_mqttConnection_t. This function should have the same\r
88  * signature as [malloc]\r
89  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).\r
90  */\r
91     void * IotMqtt_MallocConnection( size_t size );\r
92 \r
93 /**\r
94  * @brief Free an #_mqttConnection_t. This function should have the same\r
95  * signature as [free]\r
96  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).\r
97  */\r
98     void IotMqtt_FreeConnection( void * ptr );\r
99 \r
100 /**\r
101  * @brief Allocate memory for an MQTT packet. This function should have the\r
102  * same signature as [malloc]\r
103  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).\r
104  */\r
105     #define IotMqtt_MallocMessage    Iot_MallocMessageBuffer\r
106 \r
107 /**\r
108  * @brief Free an MQTT packet. This function should have the same signature\r
109  * as [free]\r
110  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).\r
111  */\r
112     #define IotMqtt_FreeMessage      Iot_FreeMessageBuffer\r
113 \r
114 /**\r
115  * @brief Allocate an #_mqttOperation_t. This function should have the same\r
116  * signature as [malloc]\r
117  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).\r
118  */\r
119     void * IotMqtt_MallocOperation( size_t size );\r
120 \r
121 /**\r
122  * @brief Free an #_mqttOperation_t. This function should have the same\r
123  * signature as [free]\r
124  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).\r
125  */\r
126     void IotMqtt_FreeOperation( void * ptr );\r
127 \r
128 /**\r
129  * @brief Allocate an #_mqttSubscription_t. This function should have the\r
130  * same signature as [malloc]\r
131  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).\r
132  */\r
133     void * IotMqtt_MallocSubscription( size_t size );\r
134 \r
135 /**\r
136  * @brief Free an #_mqttSubscription_t. This function should have the same\r
137  * signature as [free]\r
138  * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).\r
139  */\r
140     void IotMqtt_FreeSubscription( void * ptr );\r
141 #else /* if IOT_STATIC_MEMORY_ONLY == 1 */\r
142     #include <stdlib.h>\r
143 \r
144     #ifndef IotMqtt_MallocConnection\r
145         #define IotMqtt_MallocConnection    malloc\r
146     #endif\r
147 \r
148     #ifndef IotMqtt_FreeConnection\r
149         #define IotMqtt_FreeConnection    free\r
150     #endif\r
151 \r
152     #ifndef IotMqtt_MallocMessage\r
153         #define IotMqtt_MallocMessage    malloc\r
154     #endif\r
155 \r
156     #ifndef IotMqtt_FreeMessage\r
157         #define IotMqtt_FreeMessage    free\r
158     #endif\r
159 \r
160     #ifndef IotMqtt_MallocOperation\r
161         #define IotMqtt_MallocOperation    malloc\r
162     #endif\r
163 \r
164     #ifndef IotMqtt_FreeOperation\r
165         #define IotMqtt_FreeOperation    free\r
166     #endif\r
167 \r
168     #ifndef IotMqtt_MallocSubscription\r
169         #define IotMqtt_MallocSubscription    malloc\r
170     #endif\r
171 \r
172     #ifndef IotMqtt_FreeSubscription\r
173         #define IotMqtt_FreeSubscription    free\r
174     #endif\r
175 #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */\r
176 \r
177 /**\r
178  * @cond DOXYGEN_IGNORE\r
179  * Doxygen should ignore this section.\r
180  *\r
181  * Provide default values for undefined configuration constants.\r
182  */\r
183 #ifndef AWS_IOT_MQTT_ENABLE_METRICS\r
184     #define AWS_IOT_MQTT_ENABLE_METRICS             ( 1 )\r
185 #endif\r
186 #ifndef IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES\r
187     #define IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES    ( 0 )\r
188 #endif\r
189 #ifndef IOT_MQTT_RESPONSE_WAIT_MS\r
190     #define IOT_MQTT_RESPONSE_WAIT_MS               ( 1000 )\r
191 #endif\r
192 #ifndef IOT_MQTT_RETRY_MS_CEILING\r
193     #define IOT_MQTT_RETRY_MS_CEILING               ( 60000 )\r
194 #endif\r
195 /** @endcond */\r
196 \r
197 /**\r
198  * @brief Marks the empty statement of an `else` branch.\r
199  *\r
200  * Does nothing, but allows test coverage to detect branches not taken. By default,\r
201  * this is defined to nothing. When running code coverage testing, this is defined\r
202  * to an assembly NOP.\r
203  */\r
204 #ifndef EMPTY_ELSE_MARKER\r
205     #define EMPTY_ELSE_MARKER\r
206 #endif\r
207 \r
208 /*\r
209  * Constants related to limits defined in AWS Service Limits.\r
210  *\r
211  * For details, see\r
212  * https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html\r
213  *\r
214  * Used to validate parameters if when connecting to an AWS IoT MQTT server.\r
215  */\r
216 #define AWS_IOT_MQTT_SERVER_MIN_KEEPALIVE                      ( 30 )   /**< @brief Minumum keep-alive interval accepted by AWS IoT. */\r
217 #define AWS_IOT_MQTT_SERVER_MAX_KEEPALIVE                      ( 1200 ) /**< @brief Maximum keep-alive interval accepted by AWS IoT. */\r
218 #define AWS_IOT_MQTT_SERVER_MAX_CLIENTID                       ( 128 )  /**< @brief Maximum length of client identifier accepted by AWS IoT. */\r
219 #define AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH                   ( 256 )  /**< @brief Maximum length of topic names or filters accepted by AWS IoT. */\r
220 #define AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE    ( 8 )    /**< @brief Maximum number of topic filters in a single SUBSCRIBE packet. */\r
221 \r
222 /*\r
223  * MQTT control packet type and flags. Always the first byte of an MQTT\r
224  * packet.\r
225  *\r
226  * For details, see\r
227  * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349757\r
228  */\r
229 #define MQTT_PACKET_TYPE_CONNECT                               ( ( uint8_t ) 0x10U ) /**< @brief CONNECT (client-to-server). */\r
230 #define MQTT_PACKET_TYPE_CONNACK                               ( ( uint8_t ) 0x20U ) /**< @brief CONNACK (server-to-client). */\r
231 #define MQTT_PACKET_TYPE_PUBLISH                               ( ( uint8_t ) 0x30U ) /**< @brief PUBLISH (bi-directional). */\r
232 #define MQTT_PACKET_TYPE_PUBACK                                ( ( uint8_t ) 0x40U ) /**< @brief PUBACK (server-to-client). */\r
233 #define MQTT_PACKET_TYPE_SUBSCRIBE                             ( ( uint8_t ) 0x82U ) /**< @brief SUBSCRIBE (client-to-server). */\r
234 #define MQTT_PACKET_TYPE_SUBACK                                ( ( uint8_t ) 0x90U ) /**< @brief SUBACK (server-to-client). */\r
235 #define MQTT_PACKET_TYPE_UNSUBSCRIBE                           ( ( uint8_t ) 0xa2U ) /**< @brief UNSUBSCRIBE (client-to-server). */\r
236 #define MQTT_PACKET_TYPE_UNSUBACK                              ( ( uint8_t ) 0xb0U ) /**< @brief UNSUBACK (server-to-client). */\r
237 #define MQTT_PACKET_TYPE_PINGREQ                               ( ( uint8_t ) 0xc0U ) /**< @brief PINGREQ (client-to-server). */\r
238 #define MQTT_PACKET_TYPE_PINGRESP                              ( ( uint8_t ) 0xd0U ) /**< @brief PINGRESP (server-to-client). */\r
239 #define MQTT_PACKET_TYPE_DISCONNECT                            ( ( uint8_t ) 0xe0U ) /**< @brief DISCONNECT (client-to-server). */\r
240 \r
241 /**\r
242  * @brief A value that represents an invalid remaining length.\r
243  *\r
244  * This value is greater than what is allowed by the MQTT specification.\r
245  */\r
246 #define MQTT_REMAINING_LENGTH_INVALID                          ( ( size_t ) 268435456 )\r
247 \r
248 /*---------------------- MQTT internal data structures ----------------------*/\r
249 \r
250 /**\r
251  * @cond DOXYGEN_IGNORE\r
252  * Doxygen should ignore this section.\r
253  *\r
254  * Forward declaration of MQTT connection type.\r
255  */\r
256 struct _mqttConnection;\r
257 /** @endcond */\r
258 \r
259 /**\r
260  * @brief Internal structure representing a single MQTT operation, such as\r
261  * CONNECT, SUBSCRIBE, PUBLISH, etc.\r
262  *\r
263  * Queues of these structures keeps track of all in-progress MQTT operations.\r
264  */\r
265 typedef struct _mqttOperation\r
266 {\r
267     /* Pointers to neighboring queue elements. */\r
268     IotLink_t link;                           /**< @brief List link member. */\r
269 \r
270     bool incomingPublish;                     /**< @brief Set to true if this operation an incoming PUBLISH. */\r
271     struct _mqttConnection * pMqttConnection; /**< @brief MQTT connection associated with this operation. */\r
272 \r
273     IotTaskPoolJobStorage_t jobStorage;       /**< @brief Task pool job storage associated with this operation. */\r
274     IotTaskPoolJob_t job;                     /**< @brief Task pool job associated with this operation. */\r
275 \r
276     union\r
277     {\r
278         /* If incomingPublish is false, this struct is valid. */\r
279         struct\r
280         {\r
281             /* Basic operation information. */\r
282             int32_t jobReference;        /**< @brief Tracks if a job is using this operation. Must always be 0, 1, or 2. */\r
283             IotMqttOperationType_t type; /**< @brief What operation this structure represents. */\r
284             uint32_t flags;              /**< @brief Flags passed to the function that created this operation. */\r
285             uint16_t packetIdentifier;   /**< @brief The packet identifier used with this operation. */\r
286 \r
287             /* Serialized packet and size. */\r
288             uint8_t * pMqttPacket;           /**< @brief The MQTT packet to send over the network. */\r
289             uint8_t * pPacketIdentifierHigh; /**< @brief The location of the high byte of the packet identifier in the MQTT packet. */\r
290             size_t packetSize;               /**< @brief Size of `pMqttPacket`. */\r
291 \r
292             /* How to notify of an operation's completion. */\r
293             union\r
294             {\r
295                 IotSemaphore_t waitSemaphore;   /**< @brief Semaphore to be used with @ref mqtt_function_wait. */\r
296                 IotMqttCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */\r
297             } notify;                           /**< @brief How to notify of this operation's completion. */\r
298             IotMqttError_t status;              /**< @brief Result of this operation. This is reported once a response is received. */\r
299 \r
300             union\r
301             {\r
302                 struct\r
303                 {\r
304                     uint32_t count;        /**< @brief Current number of retries. */\r
305                     uint32_t limit;        /**< @brief Maximum number of retries allowed. */\r
306                     uint32_t nextPeriodMs; /**< @brief Next retry period. */\r
307                 } retry;                   /**< @brief Additional information for PUBLISH retry. */\r
308 \r
309                 struct\r
310                 {\r
311                     uint32_t failure;      /**< @brief Flag tracking keep-alive status. */\r
312                     uint32_t keepAliveMs;     /**< @brief Keep-alive interval in milliseconds. Its max value (per spec) is 65,535,000. */\r
313                     uint32_t nextPeriodMs; /**< @brief Relative delay for next keep-alive job. */\r
314                 } ping;                    /**< @brief Additional information for keep-alive pings. */\r
315             } periodic;                    /**< @brief Additional information for periodic operations. */\r
316         } operation;\r
317 \r
318         /* If incomingPublish is true, this struct is valid. */\r
319         struct\r
320         {\r
321             IotMqttPublishInfo_t publishInfo; /**< @brief Deserialized PUBLISH. */\r
322             const void * pReceivedData;       /**< @brief Any buffer associated with this PUBLISH that should be freed. */\r
323         } publish;\r
324     } u;                                      /**< @brief Valid member depends on _mqttOperation_t.incomingPublish. */\r
325 } _mqttOperation_t;\r
326 \r
327 /**\r
328  * @brief Represents an MQTT connection.\r
329  */\r
330 typedef struct _mqttConnection\r
331 {\r
332     bool awsIotMqttMode;                             /**< @brief Specifies if this connection is to an AWS IoT MQTT server. */\r
333     bool ownNetworkConnection;                       /**< @brief Whether this MQTT connection owns its network connection. */\r
334     void * pNetworkConnection;                       /**< @brief References the transport-layer network connection. */\r
335     const IotNetworkInterface_t * pNetworkInterface; /**< @brief Network interface provided to @ref mqtt_function_connect. */\r
336     IotMqttCallbackInfo_t disconnectCallback;        /**< @brief A function to invoke when this connection is disconnected. */\r
337 \r
338     #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
339         const IotMqttSerializer_t * pSerializer; /**< @brief MQTT packet serializer overrides. */\r
340     #endif\r
341 \r
342     bool disconnected;                 /**< @brief Tracks if this connection has been disconnected. */\r
343     IotMutex_t referencesMutex;        /**< @brief Recursive mutex. Grants access to connection state and operation lists. */\r
344     int32_t references;                /**< @brief Counts callbacks and operations using this connection. */\r
345     IotListDouble_t pendingProcessing; /**< @brief List of operations waiting to be processed by a task pool routine. */\r
346     IotListDouble_t pendingResponse;   /**< @brief List of processed operations awaiting a server response. */\r
347 \r
348     IotListDouble_t subscriptionList;  /**< @brief Holds subscriptions associated with this connection. */\r
349     IotMutex_t subscriptionMutex;      /**< @brief Grants exclusive access to the subscription list. */\r
350 \r
351     _mqttOperation_t pingreq;          /**< @brief Operation used for MQTT keep-alive. */\r
352 } _mqttConnection_t;\r
353 \r
354 /**\r
355  * @brief Represents a subscription stored in an MQTT connection.\r
356  */\r
357 typedef struct _mqttSubscription\r
358 {\r
359     IotLink_t link;     /**< @brief List link member. */\r
360 \r
361     int32_t references; /**< @brief How many subscription callbacks are using this subscription. */\r
362 \r
363     /**\r
364      * @brief Tracks whether @ref mqtt_function_unsubscribe has been called for\r
365      * this subscription.\r
366      *\r
367      * If there are active subscription callbacks, @ref mqtt_function_unsubscribe\r
368      * cannot remove this subscription. Instead, it will set this flag, which\r
369      * schedules the removal of this subscription once all subscription callbacks\r
370      * terminate.\r
371      */\r
372     bool unsubscribed;\r
373 \r
374     struct\r
375     {\r
376         uint16_t identifier;        /**< @brief Packet identifier. */\r
377         size_t order;               /**< @brief Order in the packet's list of subscriptions. */\r
378     } packetInfo;                   /**< @brief Information about the SUBSCRIBE packet that registered this subscription. */\r
379 \r
380     IotMqttCallbackInfo_t callback; /**< @brief Callback information for this subscription. */\r
381 \r
382     uint16_t topicFilterLength;     /**< @brief Length of #_mqttSubscription_t.pTopicFilter. */\r
383     char pTopicFilter[];            /**< @brief The subscription topic filter. */\r
384 } _mqttSubscription_t;\r
385 \r
386 /**\r
387  * @brief Represents an MQTT packet received from the network.\r
388  *\r
389  * This struct is used to hold parameters for the deserializers so that all\r
390  * deserializers have the same function signature.\r
391  */\r
392 typedef struct _mqttPacket\r
393 {\r
394     union\r
395     {\r
396         /**\r
397          * @brief (Input) MQTT connection associated with this packet. Only used\r
398          * when deserializing SUBACKs.\r
399          */\r
400         _mqttConnection_t * pMqttConnection;\r
401 \r
402         /**\r
403          * @brief (Output) Operation representing an incoming PUBLISH. Only used\r
404          * when deserializing PUBLISHes.\r
405          */\r
406         _mqttOperation_t * pIncomingPublish;\r
407     } u;                       /**< @brief Valid member depends on packet being decoded. */\r
408 \r
409     uint8_t * pRemainingData;  /**< @brief (Input) The remaining data in MQTT packet. */\r
410     size_t remainingLength;    /**< @brief (Input) Length of the remaining data in the MQTT packet. */\r
411     uint16_t packetIdentifier; /**< @brief (Output) MQTT packet identifier. */\r
412     uint8_t type;              /**< @brief (Input) A value identifying the packet type. */\r
413 } _mqttPacket_t;\r
414 \r
415 /*-------------------- MQTT struct validation functions ---------------------*/\r
416 \r
417 /**\r
418  * @brief Check that an #IotMqttConnectInfo_t is valid.\r
419  *\r
420  * @param[in] pConnectInfo The #IotMqttConnectInfo_t to validate.\r
421  *\r
422  * @return `true` if `pConnectInfo` is valid; `false` otherwise.\r
423  */\r
424 bool _IotMqtt_ValidateConnect( const IotMqttConnectInfo_t * pConnectInfo );\r
425 \r
426 /**\r
427  * @brief Check that an #IotMqttPublishInfo_t is valid.\r
428  *\r
429  * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to\r
430  * an AWS IoT MQTT server.\r
431  * @param[in] pPublishInfo The #IotMqttPublishInfo_t to validate.\r
432  *\r
433  * @return `true` if `pPublishInfo` is valid; `false` otherwise.\r
434  */\r
435 bool _IotMqtt_ValidatePublish( bool awsIotMqttMode,\r
436                                const IotMqttPublishInfo_t * pPublishInfo );\r
437 \r
438 /**\r
439  * @brief Check that an #IotMqttOperation_t is valid and waitable.\r
440  *\r
441  * @param[in] operation The #IotMqttOperation_t to validate.\r
442  *\r
443  * @return `true` if `operation` is valid; `false` otherwise.\r
444  */\r
445 bool _IotMqtt_ValidateOperation( IotMqttOperation_t operation );\r
446 \r
447 /**\r
448  * @brief Check that a list of #IotMqttSubscription_t is valid.\r
449  *\r
450  * @param[in] operation Either #IOT_MQTT_SUBSCRIBE or #IOT_MQTT_UNSUBSCRIBE.\r
451  * Some parameters are not validated for #IOT_MQTT_UNSUBSCRIBE.\r
452  * @param[in] awsIotMqttMode Specifies if this SUBSCRIBE packet is being sent to\r
453  * an AWS IoT MQTT server.\r
454  * @param[in] pListStart First element of the list to validate.\r
455  * @param[in] listSize Number of elements in the subscription list.\r
456  *\r
457  * @return `true` if every element in the list is valid; `false` otherwise.\r
458  */\r
459 bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation,\r
460                                         bool awsIotMqttMode,\r
461                                         const IotMqttSubscription_t * pListStart,\r
462                                         size_t listSize );\r
463 \r
464 /*-------------------- MQTT packet serializer functions ---------------------*/\r
465 \r
466 /**\r
467  * @brief Get the MQTT packet type from a stream of bytes off the network.\r
468  *\r
469  * @param[in] pNetworkConnection Reference to the network connection.\r
470  * @param[in] pNetworkInterface Function pointers used to interact with the\r
471  * network.\r
472  *\r
473  * @return One of the server-to-client MQTT packet types.\r
474  *\r
475  * @note This function is only used for incoming packets, and may not work\r
476  * correctly for outgoing packets.\r
477  */\r
478 uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,\r
479                                 const IotNetworkInterface_t * pNetworkInterface );\r
480 \r
481 /**\r
482  * @brief Get the remaining length from a stream of bytes off the network.\r
483  *\r
484  * @param[in] pNetworkConnection Reference to the network connection.\r
485  * @param[in] pNetworkInterface Function pointers used to interact with the\r
486  * network.\r
487  *\r
488  * @return The remaining length; #MQTT_REMAINING_LENGTH_INVALID on error.\r
489  */\r
490 size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,\r
491                                     const IotNetworkInterface_t * pNetworkInterface );\r
492 \r
493 /**\r
494  * @brief Generate a CONNECT packet from the given parameters.\r
495  *\r
496  * @param[in] pConnectInfo User-provided CONNECT information.\r
497  * @param[out] pConnectPacket Where the CONNECT packet is written.\r
498  * @param[out] pPacketSize Size of the packet written to `pConnectPacket`.\r
499  *\r
500  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
501  */\r
502 IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
503                                           uint8_t ** pConnectPacket,\r
504                                           size_t * pPacketSize );\r
505 \r
506 /**\r
507  * @brief Deserialize a CONNACK packet.\r
508  *\r
509  * Converts the packet from a stream of bytes to an #IotMqttError_t. Also\r
510  * prints out debug log messages about the packet.\r
511  *\r
512  * @param[in,out] pConnack Pointer to an MQTT packet struct representing a CONNACK.\r
513  *\r
514  * @return #IOT_MQTT_SUCCESS if CONNACK specifies that CONNECT was accepted;\r
515  * #IOT_MQTT_SERVER_REFUSED if CONNACK specifies that CONNECT was rejected;\r
516  * #IOT_MQTT_BAD_RESPONSE if the CONNACK packet doesn't follow MQTT spec.\r
517  */\r
518 IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack );\r
519 \r
520 /**\r
521  * @brief Generate a PUBLISH packet from the given parameters.\r
522  *\r
523  * @param[in] pPublishInfo User-provided PUBLISH information.\r
524  * @param[out] pPublishPacket Where the PUBLISH packet is written.\r
525  * @param[out] pPacketSize Size of the packet written to `pPublishPacket`.\r
526  * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH.\r
527  * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier\r
528  * is written.\r
529  *\r
530  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
531  */\r
532 IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
533                                           uint8_t ** pPublishPacket,\r
534                                           size_t * pPacketSize,\r
535                                           uint16_t * pPacketIdentifier,\r
536                                           uint8_t ** pPacketIdentifierHigh );\r
537 \r
538 /**\r
539  * @brief Set the DUP bit in a QoS 1 PUBLISH packet.\r
540  *\r
541  * @param[in] pPublishPacket Pointer to the PUBLISH packet to modify.\r
542  * @param[in] pPacketIdentifierHigh The high byte of any packet identifier to modify.\r
543  * @param[out] pNewPacketIdentifier Since AWS IoT does not support the DUP flag,\r
544  * a new packet identifier is generated and should be written here. This parameter\r
545  * is only used when connected to an AWS IoT MQTT server.\r
546  *\r
547  * @note See #IotMqttPublishInfo_t for caveats with retransmission to the\r
548  * AWS IoT MQTT server.\r
549  */\r
550 void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,\r
551                              uint8_t * pPacketIdentifierHigh,\r
552                              uint16_t * pNewPacketIdentifier );\r
553 \r
554 /**\r
555  * @brief Deserialize a PUBLISH packet received from the server.\r
556  *\r
557  * Converts the packet from a stream of bytes to an #IotMqttPublishInfo_t and\r
558  * extracts the packet identifier. Also prints out debug log messages about the\r
559  * packet.\r
560  *\r
561  * @param[in,out] pPublish Pointer to an MQTT packet struct representing a PUBLISH.\r
562  *\r
563  * @return #IOT_MQTT_SUCCESS if PUBLISH is valid; #IOT_MQTT_BAD_RESPONSE\r
564  * if the PUBLISH packet doesn't follow MQTT spec.\r
565  */\r
566 IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish );\r
567 \r
568 /**\r
569  * @brief Generate a PUBACK packet for the given packet identifier.\r
570  *\r
571  * @param[in] packetIdentifier The packet identifier to place in PUBACK.\r
572  * @param[out] pPubackPacket Where the PUBACK packet is written.\r
573  * @param[out] pPacketSize Size of the packet written to `pPubackPacket`.\r
574  *\r
575  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
576  */\r
577 IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,\r
578                                          uint8_t ** pPubackPacket,\r
579                                          size_t * pPacketSize );\r
580 \r
581 /**\r
582  * @brief Deserialize a PUBACK packet.\r
583  *\r
584  * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts\r
585  * the packet identifier. Also prints out debug log messages about the packet.\r
586  *\r
587  * @param[in,out] pPuback Pointer to an MQTT packet struct representing a PUBACK.\r
588  *\r
589  * @return #IOT_MQTT_SUCCESS if PUBACK is valid; #IOT_MQTT_BAD_RESPONSE\r
590  * if the PUBACK packet doesn't follow MQTT spec.\r
591  */\r
592 IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback );\r
593 \r
594 /**\r
595  * @brief Generate a SUBSCRIBE packet from the given parameters.\r
596  *\r
597  * @param[in] pSubscriptionList User-provided array of subscriptions.\r
598  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
599  * @param[out] pSubscribePacket Where the SUBSCRIBE packet is written.\r
600  * @param[out] pPacketSize Size of the packet written to `pSubscribePacket`.\r
601  * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE.\r
602  *\r
603  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
604  */\r
605 IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
606                                             size_t subscriptionCount,\r
607                                             uint8_t ** pSubscribePacket,\r
608                                             size_t * pPacketSize,\r
609                                             uint16_t * pPacketIdentifier );\r
610 \r
611 /**\r
612  * @brief Deserialize a SUBACK packet.\r
613  *\r
614  * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts\r
615  * the packet identifier. Also prints out debug log messages about the packet.\r
616  *\r
617  * @param[in,out] pSuback Pointer to an MQTT packet struct representing a SUBACK.\r
618  *\r
619  * @return #IOT_MQTT_SUCCESS if SUBACK is valid; #IOT_MQTT_BAD_RESPONSE\r
620  * if the SUBACK packet doesn't follow MQTT spec.\r
621  */\r
622 IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback );\r
623 \r
624 /**\r
625  * @brief Generate an UNSUBSCRIBE packet from the given parameters.\r
626  *\r
627  * @param[in] pSubscriptionList User-provided array of subscriptions to remove.\r
628  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
629  * @param[out] pUnsubscribePacket Where the UNSUBSCRIBE packet is written.\r
630  * @param[out] pPacketSize Size of the packet written to `pUnsubscribePacket`.\r
631  * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE.\r
632  *\r
633  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
634  */\r
635 IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
636                                               size_t subscriptionCount,\r
637                                               uint8_t ** pUnsubscribePacket,\r
638                                               size_t * pPacketSize,\r
639                                               uint16_t * pPacketIdentifier );\r
640 \r
641 /**\r
642  * @brief Deserialize a UNSUBACK packet.\r
643  *\r
644  * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts\r
645  * the packet identifier. Also prints out debug log messages about the packet.\r
646  *\r
647  * @param[in,out] pUnsuback Pointer to an MQTT packet struct representing an UNSUBACK.\r
648  *\r
649  * @return #IOT_MQTT_SUCCESS if UNSUBACK is valid; #IOT_MQTT_BAD_RESPONSE\r
650  * if the UNSUBACK packet doesn't follow MQTT spec.\r
651  */\r
652 IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback );\r
653 \r
654 /**\r
655  * @brief Generate a PINGREQ packet.\r
656  *\r
657  * @param[out] pPingreqPacket Where the PINGREQ packet is written.\r
658  * @param[out] pPacketSize Size of the packet written to `pPingreqPacket`.\r
659  *\r
660  * @return Always returns #IOT_MQTT_SUCCESS.\r
661  */\r
662 IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,\r
663                                           size_t * pPacketSize );\r
664 \r
665 /**\r
666  * @brief Deserialize a PINGRESP packet.\r
667  *\r
668  * Converts the packet from a stream of bytes to an #IotMqttError_t. Also\r
669  * prints out debug log messages about the packet.\r
670  *\r
671  * @param[in,out] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.\r
672  *\r
673  * @return #IOT_MQTT_SUCCESS if PINGRESP is valid; #IOT_MQTT_BAD_RESPONSE\r
674  * if the PINGRESP packet doesn't follow MQTT spec.\r
675  */\r
676 IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp );\r
677 \r
678 /**\r
679  * @brief Generate a DISCONNECT packet.\r
680  *\r
681  * @param[out] pDisconnectPacket Where the DISCONNECT packet is written.\r
682  * @param[out] pPacketSize Size of the packet written to `pDisconnectPacket`.\r
683  *\r
684  * @return Always returns #IOT_MQTT_SUCCESS.\r
685  */\r
686 IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,\r
687                                              size_t * pPacketSize );\r
688 \r
689 /**\r
690  * @brief Free a packet generated by the serializer.\r
691  *\r
692  * @param[in] pPacket The packet to free.\r
693  */\r
694 void _IotMqtt_FreePacket( uint8_t * pPacket );\r
695 \r
696 /*-------------------- MQTT operation record functions ----------------------*/\r
697 \r
698 /**\r
699  * @brief Create a record for a new in-progress MQTT operation.\r
700  *\r
701  * @param[in] pMqttConnection The MQTT connection to associate with the operation.\r
702  * @param[in] flags Flags variable passed to a user-facing MQTT function.\r
703  * @param[in] pCallbackInfo User-provided callback function and parameter.\r
704  * @param[out] pNewOperation Set to point to the new operation on success.\r
705  *\r
706  * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_BAD_PARAMETER, or #IOT_MQTT_NO_MEMORY.\r
707  */\r
708 IotMqttError_t _IotMqtt_CreateOperation( _mqttConnection_t * pMqttConnection,\r
709                                          uint32_t flags,\r
710                                          const IotMqttCallbackInfo_t * pCallbackInfo,\r
711                                          _mqttOperation_t ** pNewOperation );\r
712 \r
713 /**\r
714  * @brief Decrement the job reference count of an MQTT operation and optionally\r
715  * cancel its job.\r
716  *\r
717  * Checks if the operation may be destroyed afterwards.\r
718  *\r
719  * @param[in] pOperation The MQTT operation with the job to cancel.\r
720  * @param[in] cancelJob Whether to attempt cancellation of the operation's job.\r
721  *\r
722  * @return `true` if the the operation may be safely destroyed; `false` otherwise.\r
723  */\r
724 bool _IotMqtt_DecrementOperationReferences( _mqttOperation_t * pOperation,\r
725                                             bool cancelJob );\r
726 \r
727 /**\r
728  * @brief Free resources used to record an MQTT operation. This is called when\r
729  * the operation completes.\r
730  *\r
731  * @param[in] pOperation The operation which completed.\r
732  */\r
733 void _IotMqtt_DestroyOperation( _mqttOperation_t * pOperation );\r
734 \r
735 /**\r
736  * @brief Task pool routine for processing an MQTT connection's keep-alive.\r
737  *\r
738  * @param[in] pTaskPool Pointer to the system task pool.\r
739  * @param[in] pKeepAliveJob Pointer the an MQTT connection's keep-alive job.\r
740  * @param[in] pContext Pointer to an MQTT connection, passed as an opaque context.\r
741  */\r
742 void _IotMqtt_ProcessKeepAlive( IotTaskPool_t pTaskPool,\r
743                                 IotTaskPoolJob_t pKeepAliveJob,\r
744                                 void * pContext );\r
745 \r
746 /**\r
747  * @brief Task pool routine for processing an incoming PUBLISH message.\r
748  *\r
749  * @param[in] pTaskPool Pointer to the system task pool.\r
750  * @param[in] pPublishJob Pointer to the incoming PUBLISH operation's job.\r
751  * @param[in] pContext Pointer to the incoming PUBLISH operation, passed as an\r
752  * opaque context.\r
753  */\r
754 void _IotMqtt_ProcessIncomingPublish( IotTaskPool_t pTaskPool,\r
755                                       IotTaskPoolJob_t pPublishJob,\r
756                                       void * pContext );\r
757 \r
758 /**\r
759  * @brief Task pool routine for processing an MQTT operation to send.\r
760  *\r
761  * @param[in] pTaskPool Pointer to the system task pool.\r
762  * @param[in] pSendJob Pointer to an operation's job.\r
763  * @param[in] pContext Pointer to the operation to send, passed as an opaque\r
764  * context.\r
765  */\r
766 void _IotMqtt_ProcessSend( IotTaskPool_t pTaskPool,\r
767                            IotTaskPoolJob_t pSendJob,\r
768                            void * pContext );\r
769 \r
770 /**\r
771  * @brief Task pool routine for processing a completed MQTT operation.\r
772  *\r
773  * @param[in] pTaskPool Pointer to the system task pool.\r
774  * @param[in] pOperationJob Pointer to the completed operation's job.\r
775  * @param[in] pContext Pointer to the completed operation, passed as an opaque\r
776  * context.\r
777  */\r
778 void _IotMqtt_ProcessCompletedOperation( IotTaskPool_t pTaskPool,\r
779                                          IotTaskPoolJob_t pOperationJob,\r
780                                          void * pContext );\r
781 \r
782 /**\r
783  * @brief Schedule an operation for immediate processing.\r
784  *\r
785  * @param[in] pOperation The operation to schedule.\r
786  * @param[in] jobRoutine The routine to run for the job. Must be either\r
787  * #_IotMqtt_ProcessSend, #_IotMqtt_ProcessCompletedOperation, or\r
788  * #_IotMqtt_ProcessIncomingPublish.\r
789  * @param[in] delay A delay before the operation job should be executed. Pass\r
790  * `0` to execute ASAP.\r
791  *\r
792  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_SCHEDULING_ERROR.\r
793  */\r
794 IotMqttError_t _IotMqtt_ScheduleOperation( _mqttOperation_t * pOperation,\r
795                                            IotTaskPoolRoutine_t jobRoutine,\r
796                                            uint32_t delay );\r
797 \r
798 /**\r
799  * @brief Search a list of MQTT operations pending responses using an operation\r
800  * name and packet identifier. Removes a matching operation from the list if found.\r
801  *\r
802  * @param[in] pMqttConnection The connection associated with the operation.\r
803  * @param[in] type The operation type to look for.\r
804  * @param[in] pPacketIdentifier A packet identifier to match. Pass `NULL` to ignore.\r
805  *\r
806  * @return Pointer to any matching operation; `NULL` if no match was found.\r
807  */\r
808 _mqttOperation_t * _IotMqtt_FindOperation( _mqttConnection_t * pMqttConnection,\r
809                                            IotMqttOperationType_t type,\r
810                                            const uint16_t * pPacketIdentifier );\r
811 \r
812 /**\r
813  * @brief Notify of a completed MQTT operation.\r
814  *\r
815  * @param[in] pOperation The MQTT operation which completed.\r
816  *\r
817  * Depending on the parameters passed to a user-facing MQTT function, the\r
818  * notification will cause @ref mqtt_function_wait to return or invoke a\r
819  * user-provided callback.\r
820  */\r
821 void _IotMqtt_Notify( _mqttOperation_t * pOperation );\r
822 \r
823 /*----------------- MQTT subscription management functions ------------------*/\r
824 \r
825 /**\r
826  * @brief Add an array of subscriptions to the subscription manager.\r
827  *\r
828  * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.\r
829  * @param[in] subscribePacketIdentifier Packet identifier for the subscriptions'\r
830  * SUBSCRIBE packet.\r
831  * @param[in] pSubscriptionList The first element in the array.\r
832  * @param[in] subscriptionCount Number of elements in `pSubscriptionList`.\r
833  *\r
834  * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.\r
835  */\r
836 IotMqttError_t _IotMqtt_AddSubscriptions( _mqttConnection_t * pMqttConnection,\r
837                                           uint16_t subscribePacketIdentifier,\r
838                                           const IotMqttSubscription_t * pSubscriptionList,\r
839                                           size_t subscriptionCount );\r
840 \r
841 /**\r
842  * @brief Process a received PUBLISH from the server, invoking any subscription\r
843  * callbacks that have a matching topic filter.\r
844  *\r
845  * @param[in] pMqttConnection The MQTT connection associated with the received\r
846  * PUBLISH.\r
847  * @param[in] pCallbackParam The parameter to pass to a PUBLISH callback.\r
848  */\r
849 void _IotMqtt_InvokeSubscriptionCallback( _mqttConnection_t * pMqttConnection,\r
850                                           IotMqttCallbackParam_t * pCallbackParam );\r
851 \r
852 /**\r
853  * @brief Remove a single subscription from the subscription manager by\r
854  * packetIdentifier and order.\r
855  *\r
856  * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.\r
857  * @param[in] packetIdentifier The packet identifier associated with the subscription's\r
858  * SUBSCRIBE packet.\r
859  * @param[in] order The order of the subscription in the SUBSCRIBE packet.\r
860  * Pass `-1` to ignore order and remove all subscriptions for `packetIdentifier`.\r
861  */\r
862 void _IotMqtt_RemoveSubscriptionByPacket( _mqttConnection_t * pMqttConnection,\r
863                                           uint16_t packetIdentifier,\r
864                                           int32_t order );\r
865 \r
866 /**\r
867  * @brief Remove an array of subscriptions from the subscription manager by\r
868  * topic filter.\r
869  *\r
870  * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.\r
871  * @param[in] pSubscriptionList The first element in the array.\r
872  * @param[in] subscriptionCount Number of elements in `pSubscriptionList`.\r
873  */\r
874 void _IotMqtt_RemoveSubscriptionByTopicFilter( _mqttConnection_t * pMqttConnection,\r
875                                                const IotMqttSubscription_t * pSubscriptionList,\r
876                                                size_t subscriptionCount );\r
877 \r
878 /*------------------ MQTT connection management functions -------------------*/\r
879 \r
880 /**\r
881  * @brief Attempt to increment the reference count of an MQTT connection.\r
882  *\r
883  * @param[in] pMqttConnection The referenced MQTT connection.\r
884  *\r
885  * @return `true` if the reference count was incremented; `false` otherwise. The\r
886  * reference count will not be incremented for a disconnected connection.\r
887  */\r
888 bool _IotMqtt_IncrementConnectionReferences( _mqttConnection_t * pMqttConnection );\r
889 \r
890 /**\r
891  * @brief Decrement the reference count of an MQTT connection.\r
892  *\r
893  * Also destroys an unreferenced MQTT connection.\r
894  *\r
895  * @param[in] pMqttConnection The referenced MQTT connection.\r
896  */\r
897 void _IotMqtt_DecrementConnectionReferences( _mqttConnection_t * pMqttConnection );\r
898 \r
899 /**\r
900  * @brief Read the next available byte on a network connection.\r
901  *\r
902  * @param[in] pNetworkConnection Reference to the network connection.\r
903  * @param[in] pNetworkInterface Function pointers used to interact with the\r
904  * network.\r
905  * @param[out] pIncomingByte The byte read from the network.\r
906  *\r
907  * @return `true` if a byte was successfully received from the network; `false`\r
908  * otherwise.\r
909  */\r
910 bool _IotMqtt_GetNextByte( void * pNetworkConnection,\r
911                            const IotNetworkInterface_t * pNetworkInterface,\r
912                            uint8_t * pIncomingByte );\r
913 \r
914 /**\r
915  * @brief Closes the network connection associated with an MQTT connection.\r
916  *\r
917  * A network disconnect function must be set in the network interface for the\r
918  * network connection to be closed.\r
919  *\r
920  * @param[in] disconnectReason A reason to pass to the connection's disconnect\r
921  * callback.\r
922  * @param[in] pMqttConnection The MQTT connection with the network connection\r
923  * to close.\r
924  */\r
925 void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason,\r
926                                       _mqttConnection_t * pMqttConnection );\r
927 \r
928 #endif /* ifndef IOT_MQTT_INTERNAL_H_ */\r