]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_network.c
169a292df791479bd14cad9e48514ad49929348b
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / mqtt / src / iot_mqtt_network.c
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_network.c\r
28  * @brief Implements functions involving transport layer connections.\r
29  */\r
30 \r
31 /* The config header is always included first. */\r
32 #include "iot_config.h"\r
33 \r
34 /* Standard includes. */\r
35 #include <string.h>\r
36 \r
37 /* Error handling include. */\r
38 #include "private/iot_error.h"\r
39 \r
40 /* MQTT internal include. */\r
41 #include "private/iot_mqtt_internal.h"\r
42 \r
43 /* Platform layer includes. */\r
44 #include "platform/iot_threads.h"\r
45 \r
46 /*-----------------------------------------------------------*/\r
47 \r
48 /**\r
49  * @brief Check if an incoming packet type is valid.\r
50  *\r
51  * @param[in] packetType The packet type to check.\r
52  *\r
53  * @return `true` if the packet type is valid; `false` otherwise.\r
54  */\r
55 static bool _incomingPacketValid( uint8_t packetType );\r
56 \r
57 /**\r
58  * @brief Get an incoming MQTT packet from the network.\r
59  *\r
60  * @param[in] pNetworkConnection Network connection to use for receive, which\r
61  * may be different from the network connection associated with the MQTT connection.\r
62  * @param[in] pMqttConnection The associated MQTT connection.\r
63  * @param[out] pIncomingPacket Output parameter for the incoming packet.\r
64  *\r
65  * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY or #IOT_MQTT_BAD_RESPONSE.\r
66  */\r
67 static IotMqttError_t _getIncomingPacket( void * pNetworkConnection,\r
68                                           const _mqttConnection_t * pMqttConnection,\r
69                                           _mqttPacket_t * pIncomingPacket );\r
70 \r
71 /**\r
72  * @brief Deserialize a packet received from the network.\r
73  *\r
74  * @param[in] pMqttConnection The associated MQTT connection.\r
75  * @param[in] pIncomingPacket The packet received from the network.\r
76  *\r
77  * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY, #IOT_MQTT_NETWORK_ERROR,\r
78  * #IOT_MQTT_SCHEDULING_ERROR, #IOT_MQTT_BAD_RESPONSE, or #IOT_MQTT_SERVER_REFUSED.\r
79  */\r
80 static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection,\r
81                                                   _mqttPacket_t * pIncomingPacket );\r
82 \r
83 /**\r
84  * @brief Send a PUBACK for a received QoS 1 PUBLISH packet.\r
85  *\r
86  * @param[in] pMqttConnection Which connection the PUBACK should be sent over.\r
87  * @param[in] packetIdentifier Which packet identifier to include in PUBACK.\r
88  */\r
89 static void _sendPuback( _mqttConnection_t * pMqttConnection,\r
90                          uint16_t packetIdentifier );\r
91 \r
92 /*-----------------------------------------------------------*/\r
93 \r
94 static bool _incomingPacketValid( uint8_t packetType )\r
95 {\r
96     bool status = true;\r
97 \r
98     /* Check packet type. Mask out lower bits to ignore flags. */\r
99     switch( packetType & 0xf0 )\r
100     {\r
101         /* Valid incoming packet types. */\r
102         case MQTT_PACKET_TYPE_CONNACK:\r
103         case MQTT_PACKET_TYPE_PUBLISH:\r
104         case MQTT_PACKET_TYPE_PUBACK:\r
105         case MQTT_PACKET_TYPE_SUBACK:\r
106         case MQTT_PACKET_TYPE_UNSUBACK:\r
107         case MQTT_PACKET_TYPE_PINGRESP:\r
108             break;\r
109 \r
110         /* Any other packet type is invalid. */\r
111         default:\r
112             status = false;\r
113             break;\r
114     }\r
115 \r
116     return status;\r
117 }\r
118 \r
119 /*-----------------------------------------------------------*/\r
120 \r
121 static IotMqttError_t _getIncomingPacket( void * pNetworkConnection,\r
122                                           const _mqttConnection_t * pMqttConnection,\r
123                                           _mqttPacket_t * pIncomingPacket )\r
124 {\r
125     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
126     size_t dataBytesRead = 0;\r
127 \r
128     /* Default functions for retrieving packet type and length. */\r
129     uint8_t ( * getPacketType )( void *,\r
130                                  const IotNetworkInterface_t * ) = _IotMqtt_GetPacketType;\r
131     size_t ( * getRemainingLength )( void *,\r
132                                      const IotNetworkInterface_t * ) = _IotMqtt_GetRemainingLength;\r
133 \r
134     /* No buffer for remaining data should be allocated. */\r
135     IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL );\r
136     IotMqtt_Assert( pIncomingPacket->remainingLength == 0 );\r
137 \r
138     /* Choose packet type and length functions. */\r
139     #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
140         if( pMqttConnection->pSerializer != NULL )\r
141         {\r
142             if( pMqttConnection->pSerializer->getPacketType != NULL )\r
143             {\r
144                 getPacketType = pMqttConnection->pSerializer->getPacketType;\r
145             }\r
146             else\r
147             {\r
148                 EMPTY_ELSE_MARKER;\r
149             }\r
150 \r
151             if( pMqttConnection->pSerializer->getRemainingLength != NULL )\r
152             {\r
153                 getRemainingLength = pMqttConnection->pSerializer->getRemainingLength;\r
154             }\r
155             else\r
156             {\r
157                 EMPTY_ELSE_MARKER;\r
158             }\r
159         }\r
160         else\r
161         {\r
162             EMPTY_ELSE_MARKER;\r
163         }\r
164     #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
165 \r
166     /* Read the packet type, which is the first byte available. */\r
167     pIncomingPacket->type = getPacketType( pNetworkConnection,\r
168                                            pMqttConnection->pNetworkInterface );\r
169 \r
170     /* Check that the incoming packet type is valid. */\r
171     if( _incomingPacketValid( pIncomingPacket->type ) == false )\r
172     {\r
173         IotLogError( "(MQTT connection %p) Unknown packet type %02x received.",\r
174                      pMqttConnection,\r
175                      pIncomingPacket->type );\r
176 \r
177         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
178     }\r
179     else\r
180     {\r
181         EMPTY_ELSE_MARKER;\r
182     }\r
183 \r
184     /* Read the remaining length. */\r
185     pIncomingPacket->remainingLength = getRemainingLength( pNetworkConnection,\r
186                                                            pMqttConnection->pNetworkInterface );\r
187 \r
188     if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )\r
189     {\r
190         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
191     }\r
192     else\r
193     {\r
194         EMPTY_ELSE_MARKER;\r
195     }\r
196 \r
197     /* Allocate a buffer for the remaining data and read the data. */\r
198     if( pIncomingPacket->remainingLength > 0 )\r
199     {\r
200         pIncomingPacket->pRemainingData = IotMqtt_MallocMessage( pIncomingPacket->remainingLength );\r
201 \r
202         if( pIncomingPacket->pRemainingData == NULL )\r
203         {\r
204             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
205         }\r
206         else\r
207         {\r
208             EMPTY_ELSE_MARKER;\r
209         }\r
210 \r
211         dataBytesRead = pMqttConnection->pNetworkInterface->receive( pNetworkConnection,\r
212                                                                      pIncomingPacket->pRemainingData,\r
213                                                                      pIncomingPacket->remainingLength );\r
214 \r
215         if( dataBytesRead != pIncomingPacket->remainingLength )\r
216         {\r
217             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
218         }\r
219         else\r
220         {\r
221             EMPTY_ELSE_MARKER;\r
222         }\r
223     }\r
224     else\r
225     {\r
226         EMPTY_ELSE_MARKER;\r
227     }\r
228 \r
229     /* Clean up on error. */\r
230     IOT_FUNCTION_CLEANUP_BEGIN();\r
231 \r
232     if( status != IOT_MQTT_SUCCESS )\r
233     {\r
234         if( pIncomingPacket->pRemainingData != NULL )\r
235         {\r
236             IotMqtt_FreeMessage( pIncomingPacket->pRemainingData );\r
237         }\r
238         else\r
239         {\r
240             EMPTY_ELSE_MARKER;\r
241         }\r
242     }\r
243     else\r
244     {\r
245         EMPTY_ELSE_MARKER;\r
246     }\r
247 \r
248     IOT_FUNCTION_CLEANUP_END();\r
249 }\r
250 \r
251 /*-----------------------------------------------------------*/\r
252 \r
253 static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection,\r
254                                                   _mqttPacket_t * pIncomingPacket )\r
255 {\r
256     IotMqttError_t status = IOT_MQTT_STATUS_PENDING;\r
257     _mqttOperation_t * pOperation = NULL;\r
258 \r
259     /* Deserializer function. */\r
260     IotMqttError_t ( * deserialize )( _mqttPacket_t * ) = NULL;\r
261 \r
262     /* A buffer for remaining data must be allocated if remaining length is not 0. */\r
263     IotMqtt_Assert( ( pIncomingPacket->remainingLength > 0 ) ==\r
264                     ( pIncomingPacket->pRemainingData != NULL ) );\r
265 \r
266     /* Only valid packets should be given to this function. */\r
267     IotMqtt_Assert( _incomingPacketValid( pIncomingPacket->type ) == true );\r
268 \r
269     /* Mask out the low bits of packet type to ignore flags. */\r
270     switch( ( pIncomingPacket->type & 0xf0 ) )\r
271     {\r
272         case MQTT_PACKET_TYPE_CONNACK:\r
273             IotLogDebug( "(MQTT connection %p) CONNACK in data stream.", pMqttConnection );\r
274 \r
275             /* Choose CONNACK deserializer. */\r
276             deserialize = _IotMqtt_DeserializeConnack;\r
277 \r
278             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
279                 if( pMqttConnection->pSerializer != NULL )\r
280                 {\r
281                     if( pMqttConnection->pSerializer->deserialize.connack != NULL )\r
282                     {\r
283                         deserialize = pMqttConnection->pSerializer->deserialize.connack;\r
284                     }\r
285                     else\r
286                     {\r
287                         EMPTY_ELSE_MARKER;\r
288                     }\r
289                 }\r
290                 else\r
291                 {\r
292                     EMPTY_ELSE_MARKER;\r
293                 }\r
294             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
295 \r
296             /* Deserialize CONNACK and notify of result. */\r
297             status = deserialize( pIncomingPacket );\r
298             pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
299                                                  IOT_MQTT_CONNECT,\r
300                                                  NULL );\r
301 \r
302             if( pOperation != NULL )\r
303             {\r
304                 pOperation->u.operation.status = status;\r
305                 _IotMqtt_Notify( pOperation );\r
306             }\r
307             else\r
308             {\r
309                 EMPTY_ELSE_MARKER;\r
310             }\r
311 \r
312             break;\r
313 \r
314         case MQTT_PACKET_TYPE_PUBLISH:\r
315             IotLogDebug( "(MQTT connection %p) PUBLISH in data stream.", pMqttConnection );\r
316 \r
317             /* Allocate memory to handle the incoming PUBLISH. */\r
318             pOperation = IotMqtt_MallocOperation( sizeof( _mqttOperation_t ) );\r
319 \r
320             if( pOperation == NULL )\r
321             {\r
322                 IotLogWarn( "Failed to allocate memory for incoming PUBLISH." );\r
323                 status = IOT_MQTT_NO_MEMORY;\r
324 \r
325                 break;\r
326             }\r
327             else\r
328             {\r
329                 /* Set the members of the incoming PUBLISH operation. */\r
330                 ( void ) memset( pOperation, 0x00, sizeof( _mqttOperation_t ) );\r
331                 pOperation->incomingPublish = true;\r
332                 pOperation->pMqttConnection = pMqttConnection;\r
333                 pIncomingPacket->u.pIncomingPublish = pOperation;\r
334             }\r
335 \r
336             /* Choose a PUBLISH deserializer. */\r
337             deserialize = _IotMqtt_DeserializePublish;\r
338 \r
339             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
340                 if( pMqttConnection->pSerializer != NULL )\r
341                 {\r
342                     if( pMqttConnection->pSerializer->deserialize.publish != NULL )\r
343                     {\r
344                         deserialize = pMqttConnection->pSerializer->deserialize.publish;\r
345                     }\r
346                     else\r
347                     {\r
348                         EMPTY_ELSE_MARKER;\r
349                     }\r
350                 }\r
351                 else\r
352                 {\r
353                     EMPTY_ELSE_MARKER;\r
354                 }\r
355             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
356 \r
357             /* Deserialize incoming PUBLISH. */\r
358             status = deserialize( pIncomingPacket );\r
359 \r
360             if( status == IOT_MQTT_SUCCESS )\r
361             {\r
362                 /* Send a PUBACK for QoS 1 PUBLISH. */\r
363                 if( pOperation->u.publish.publishInfo.qos == IOT_MQTT_QOS_1 )\r
364                 {\r
365                     _sendPuback( pMqttConnection, pIncomingPacket->packetIdentifier );\r
366                 }\r
367                 else\r
368                 {\r
369                     EMPTY_ELSE_MARKER;\r
370                 }\r
371 \r
372                 /* Transfer ownership of the received MQTT packet to the PUBLISH operation. */\r
373                 pOperation->u.publish.pReceivedData = pIncomingPacket->pRemainingData;\r
374                 pIncomingPacket->pRemainingData = NULL;\r
375 \r
376                 /* Add the PUBLISH to the list of operations pending processing. */\r
377                 IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
378                 IotListDouble_InsertHead( &( pMqttConnection->pendingProcessing ),\r
379                                           &( pOperation->link ) );\r
380                 IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
381 \r
382                 /* Increment the MQTT connection reference count before scheduling an\r
383                  * incoming PUBLISH. */\r
384                 if( _IotMqtt_IncrementConnectionReferences( pMqttConnection ) == true )\r
385                 {\r
386                     /* Schedule PUBLISH for callback invocation. */\r
387                     status = _IotMqtt_ScheduleOperation( pOperation, _IotMqtt_ProcessIncomingPublish, 0 );\r
388                 }\r
389                 else\r
390                 {\r
391                     status = IOT_MQTT_NETWORK_ERROR;\r
392                 }\r
393             }\r
394             else\r
395             {\r
396                 EMPTY_ELSE_MARKER;\r
397             }\r
398 \r
399             /* Free PUBLISH operation on error. */\r
400             if( status != IOT_MQTT_SUCCESS )\r
401             {\r
402                 /* Check ownership of the received MQTT packet. */\r
403                 if( pOperation->u.publish.pReceivedData != NULL )\r
404                 {\r
405                     /* Retrieve the pointer MQTT packet pointer so it may be freed later. */\r
406                     IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL );\r
407                     pIncomingPacket->pRemainingData = ( uint8_t * ) pOperation->u.publish.pReceivedData;\r
408                 }\r
409                 else\r
410                 {\r
411                     EMPTY_ELSE_MARKER;\r
412                 }\r
413 \r
414                 /* Remove operation from pending processing list. */\r
415                 IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
416 \r
417                 if( IotLink_IsLinked( &( pOperation->link ) ) == true )\r
418                 {\r
419                     IotListDouble_Remove( &( pOperation->link ) );\r
420                 }\r
421                 else\r
422                 {\r
423                     EMPTY_ELSE_MARKER;\r
424                 }\r
425 \r
426                 IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
427 \r
428                 IotMqtt_Assert( pOperation != NULL );\r
429                 IotMqtt_FreeOperation( pOperation );\r
430             }\r
431             else\r
432             {\r
433                 EMPTY_ELSE_MARKER;\r
434             }\r
435 \r
436             break;\r
437 \r
438         case MQTT_PACKET_TYPE_PUBACK:\r
439             IotLogDebug( "(MQTT connection %p) PUBACK in data stream.", pMqttConnection );\r
440 \r
441             /* Choose PUBACK deserializer. */\r
442             deserialize = _IotMqtt_DeserializePuback;\r
443 \r
444             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
445                 if( pMqttConnection->pSerializer != NULL )\r
446                 {\r
447                     if( pMqttConnection->pSerializer->deserialize.puback != NULL )\r
448                     {\r
449                         deserialize = pMqttConnection->pSerializer->deserialize.puback;\r
450                     }\r
451                     else\r
452                     {\r
453                         EMPTY_ELSE_MARKER;\r
454                     }\r
455                 }\r
456                 else\r
457                 {\r
458                     EMPTY_ELSE_MARKER;\r
459                 }\r
460             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
461 \r
462             /* Deserialize PUBACK and notify of result. */\r
463             status = deserialize( pIncomingPacket );\r
464             pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
465                                                  IOT_MQTT_PUBLISH_TO_SERVER,\r
466                                                  &( pIncomingPacket->packetIdentifier ) );\r
467 \r
468             if( pOperation != NULL )\r
469             {\r
470                 pOperation->u.operation.status = status;\r
471                 _IotMqtt_Notify( pOperation );\r
472             }\r
473             else\r
474             {\r
475                 EMPTY_ELSE_MARKER;\r
476             }\r
477 \r
478             break;\r
479 \r
480         case MQTT_PACKET_TYPE_SUBACK:\r
481             IotLogDebug( "(MQTT connection %p) SUBACK in data stream.", pMqttConnection );\r
482 \r
483             /* Choose SUBACK deserializer. */\r
484             deserialize = _IotMqtt_DeserializeSuback;\r
485 \r
486             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
487                 if( pMqttConnection->pSerializer != NULL )\r
488                 {\r
489                     if( pMqttConnection->pSerializer->deserialize.suback != NULL )\r
490                     {\r
491                         deserialize = pMqttConnection->pSerializer->deserialize.suback;\r
492                     }\r
493                     else\r
494                     {\r
495                         EMPTY_ELSE_MARKER;\r
496                     }\r
497                 }\r
498                 else\r
499                 {\r
500                     EMPTY_ELSE_MARKER;\r
501                 }\r
502             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
503 \r
504             /* Deserialize SUBACK and notify of result. */\r
505             pIncomingPacket->u.pMqttConnection = pMqttConnection;\r
506             status = deserialize( pIncomingPacket );\r
507             pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
508                                                  IOT_MQTT_SUBSCRIBE,\r
509                                                  &( pIncomingPacket->packetIdentifier ) );\r
510 \r
511             if( pOperation != NULL )\r
512             {\r
513                 pOperation->u.operation.status = status;\r
514                 _IotMqtt_Notify( pOperation );\r
515             }\r
516             else\r
517             {\r
518                 EMPTY_ELSE_MARKER;\r
519             }\r
520 \r
521             break;\r
522 \r
523         case MQTT_PACKET_TYPE_UNSUBACK:\r
524             IotLogDebug( "(MQTT connection %p) UNSUBACK in data stream.", pMqttConnection );\r
525 \r
526             /* Choose UNSUBACK deserializer. */\r
527             deserialize = _IotMqtt_DeserializeUnsuback;\r
528 \r
529             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
530                 if( pMqttConnection->pSerializer != NULL )\r
531                 {\r
532                     if( pMqttConnection->pSerializer->deserialize.unsuback != NULL )\r
533                     {\r
534                         deserialize = pMqttConnection->pSerializer->deserialize.unsuback;\r
535                     }\r
536                     else\r
537                     {\r
538                         EMPTY_ELSE_MARKER;\r
539                     }\r
540                 }\r
541                 else\r
542                 {\r
543                     EMPTY_ELSE_MARKER;\r
544                 }\r
545             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
546 \r
547             /* Deserialize UNSUBACK and notify of result. */\r
548             status = deserialize( pIncomingPacket );\r
549             pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
550                                                  IOT_MQTT_UNSUBSCRIBE,\r
551                                                  &( pIncomingPacket->packetIdentifier ) );\r
552 \r
553             if( pOperation != NULL )\r
554             {\r
555                 pOperation->u.operation.status = status;\r
556                 _IotMqtt_Notify( pOperation );\r
557             }\r
558             else\r
559             {\r
560                 EMPTY_ELSE_MARKER;\r
561             }\r
562 \r
563             break;\r
564 \r
565         default:\r
566             /* The only remaining valid type is PINGRESP. */\r
567             IotMqtt_Assert( ( pIncomingPacket->type & 0xf0 ) == MQTT_PACKET_TYPE_PINGRESP );\r
568             IotLogDebug( "(MQTT connection %p) PINGRESP in data stream.", pMqttConnection );\r
569 \r
570             /* Choose PINGRESP deserializer. */\r
571             deserialize = _IotMqtt_DeserializePingresp;\r
572 \r
573             #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
574                 if( pMqttConnection->pSerializer != NULL )\r
575                 {\r
576                     if( pMqttConnection->pSerializer->deserialize.pingresp != NULL )\r
577                     {\r
578                         deserialize = pMqttConnection->pSerializer->deserialize.pingresp;\r
579                     }\r
580                     else\r
581                     {\r
582                         EMPTY_ELSE_MARKER;\r
583                     }\r
584                 }\r
585                 else\r
586                 {\r
587                     EMPTY_ELSE_MARKER;\r
588                 }\r
589             #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
590 \r
591             /* Deserialize PINGRESP. */\r
592             status = deserialize( pIncomingPacket );\r
593 \r
594             if( status == IOT_MQTT_SUCCESS )\r
595             {\r
596                 IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
597 \r
598                 if( pMqttConnection->keepAliveFailure == false )\r
599                 {\r
600                     IotLogWarn( "(MQTT connection %p) Unexpected PINGRESP received.",\r
601                                 pMqttConnection );\r
602                 }\r
603                 else\r
604                 {\r
605                     IotLogDebug( "(MQTT connection %p) PINGRESP successfully parsed.",\r
606                                  pMqttConnection );\r
607 \r
608                     pMqttConnection->keepAliveFailure = false;\r
609                 }\r
610 \r
611                 IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
612             }\r
613             else\r
614             {\r
615                 EMPTY_ELSE_MARKER;\r
616             }\r
617 \r
618             break;\r
619     }\r
620 \r
621     if( status != IOT_MQTT_SUCCESS )\r
622     {\r
623         IotLogError( "(MQTT connection %p) Packet parser status %s.",\r
624                      pMqttConnection,\r
625                      IotMqtt_strerror( status ) );\r
626     }\r
627     else\r
628     {\r
629         EMPTY_ELSE_MARKER;\r
630     }\r
631 \r
632     return status;\r
633 }\r
634 \r
635 /*-----------------------------------------------------------*/\r
636 \r
637 static void _sendPuback( _mqttConnection_t * pMqttConnection,\r
638                          uint16_t packetIdentifier )\r
639 {\r
640     IotMqttError_t serializeStatus = IOT_MQTT_SUCCESS;\r
641     uint8_t * pPuback = NULL;\r
642     size_t pubackSize = 0, bytesSent = 0;\r
643 \r
644     /* Default PUBACK serializer and free packet functions. */\r
645     IotMqttError_t ( * serializePuback )( uint16_t,\r
646                                           uint8_t **,\r
647                                           size_t * ) = _IotMqtt_SerializePuback;\r
648     void ( * freePacket )( uint8_t * ) = _IotMqtt_FreePacket;\r
649 \r
650     IotLogDebug( "(MQTT connection %p) Sending PUBACK for received PUBLISH %hu.",\r
651                  pMqttConnection,\r
652                  packetIdentifier );\r
653 \r
654     /* Choose PUBACK serializer and free packet functions. */\r
655     #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
656         if( pMqttConnection->pSerializer != NULL )\r
657         {\r
658             if( pMqttConnection->pSerializer->serialize.puback != NULL )\r
659             {\r
660                 serializePuback = pMqttConnection->pSerializer->serialize.puback;\r
661             }\r
662             else\r
663             {\r
664                 EMPTY_ELSE_MARKER;\r
665             }\r
666         }\r
667         else\r
668         {\r
669             EMPTY_ELSE_MARKER;\r
670         }\r
671     #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
672     #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
673         if( pMqttConnection->pSerializer != NULL )\r
674         {\r
675             if( pMqttConnection->pSerializer->freePacket != NULL )\r
676             {\r
677                 freePacket = pMqttConnection->pSerializer->freePacket;\r
678             }\r
679             else\r
680             {\r
681                 EMPTY_ELSE_MARKER;\r
682             }\r
683         }\r
684         else\r
685         {\r
686             EMPTY_ELSE_MARKER;\r
687         }\r
688     #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
689 \r
690     /* Generate a PUBACK packet from the packet identifier. */\r
691     serializeStatus = serializePuback( packetIdentifier,\r
692                                        &pPuback,\r
693                                        &pubackSize );\r
694 \r
695     if( serializeStatus != IOT_MQTT_SUCCESS )\r
696     {\r
697         IotLogWarn( "(MQTT connection %p) Failed to generate PUBACK packet for "\r
698                     "received PUBLISH %hu.",\r
699                     pMqttConnection,\r
700                     packetIdentifier );\r
701     }\r
702     else\r
703     {\r
704         bytesSent = pMqttConnection->pNetworkInterface->send( pMqttConnection->pNetworkConnection,\r
705                                                               pPuback,\r
706                                                               pubackSize );\r
707 \r
708         if( bytesSent != pubackSize )\r
709         {\r
710             IotLogWarn( "(MQTT connection %p) Failed to send PUBACK for received"\r
711                         " PUBLISH %hu.",\r
712                         pMqttConnection,\r
713                         packetIdentifier );\r
714         }\r
715         else\r
716         {\r
717             IotLogDebug( "(MQTT connection %p) PUBACK for received PUBLISH %hu sent.",\r
718                          pMqttConnection,\r
719                          packetIdentifier );\r
720         }\r
721 \r
722         freePacket( pPuback );\r
723     }\r
724 }\r
725 \r
726 /*-----------------------------------------------------------*/\r
727 \r
728 bool _IotMqtt_GetNextByte( void * pNetworkConnection,\r
729                            const IotNetworkInterface_t * pNetworkInterface,\r
730                            uint8_t * pIncomingByte )\r
731 {\r
732     bool status = false;\r
733     uint8_t incomingByte = 0;\r
734     size_t bytesReceived = 0;\r
735 \r
736     /* Attempt to read 1 byte. */\r
737     bytesReceived = pNetworkInterface->receive( pNetworkConnection,\r
738                                                 &incomingByte,\r
739                                                 1 );\r
740 \r
741     /* Set the output parameter and return success if 1 byte was read. */\r
742     if( bytesReceived == 1 )\r
743     {\r
744         *pIncomingByte = incomingByte;\r
745         status = true;\r
746     }\r
747     else\r
748     {\r
749         /* Network receive must return 0 on failure. */\r
750         IotMqtt_Assert( bytesReceived == 0 );\r
751     }\r
752 \r
753     return status;\r
754 }\r
755 \r
756 /*-----------------------------------------------------------*/\r
757 \r
758 void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason,\r
759                                       _mqttConnection_t * pMqttConnection )\r
760 {\r
761     IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS;\r
762     IotNetworkError_t closeStatus = IOT_NETWORK_SUCCESS;\r
763     IotMqttCallbackParam_t callbackParam = { .u.message = { 0 } };\r
764 \r
765     /* Mark the MQTT connection as disconnected and the keep-alive as failed. */\r
766     IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
767     pMqttConnection->disconnected = true;\r
768     pMqttConnection->keepAliveFailure = true;\r
769 \r
770     if( pMqttConnection->keepAliveMs != 0 )\r
771     {\r
772         /* Keep-alive must have a PINGREQ allocated. */\r
773         IotMqtt_Assert( pMqttConnection->pPingreqPacket != NULL );\r
774         IotMqtt_Assert( pMqttConnection->pingreqPacketSize != 0 );\r
775 \r
776         /* PINGREQ provides a reference to the connection, so reference count must\r
777          * be nonzero. */\r
778         IotMqtt_Assert( pMqttConnection->references > 0 );\r
779 \r
780         /* Attempt to cancel the keep-alive job. */\r
781         taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL,\r
782                                                 pMqttConnection->keepAliveJob,\r
783                                                 NULL );\r
784 \r
785         /* If the keep-alive job was not canceled, it must be already executing.\r
786          * Any other return value is invalid. */\r
787         IotMqtt_Assert( ( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) ||\r
788                         ( taskPoolStatus == IOT_TASKPOOL_CANCEL_FAILED ) );\r
789 \r
790         /* Clean up keep-alive if its job was successfully canceled. Otherwise,\r
791          * the executing keep-alive job will clean up itself. */\r
792         if( taskPoolStatus == IOT_TASKPOOL_SUCCESS )\r
793         {\r
794             /* Clean up PINGREQ packet and job. */\r
795             _IotMqtt_FreePacket( pMqttConnection->pPingreqPacket );\r
796 \r
797             /* Clear data about the keep-alive. */\r
798             pMqttConnection->keepAliveMs = 0;\r
799             pMqttConnection->pPingreqPacket = NULL;\r
800             pMqttConnection->pingreqPacketSize = 0;\r
801 \r
802             /* Keep-alive is cleaned up; decrement reference count. Since this\r
803              * function must be followed with a call to DISCONNECT, a check to\r
804              * destroy the connection is not done here. */\r
805             pMqttConnection->references--;\r
806 \r
807             IotLogDebug( "(MQTT connection %p) Keep-alive job canceled and cleaned up.",\r
808                          pMqttConnection );\r
809         }\r
810         else\r
811         {\r
812             EMPTY_ELSE_MARKER;\r
813         }\r
814     }\r
815     else\r
816     {\r
817         EMPTY_ELSE_MARKER;\r
818     }\r
819 \r
820     IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
821 \r
822     /* Close the network connection. */\r
823     if( pMqttConnection->pNetworkInterface->close != NULL )\r
824     {\r
825         closeStatus = pMqttConnection->pNetworkInterface->close( pMqttConnection->pNetworkConnection );\r
826 \r
827         if( closeStatus == IOT_NETWORK_SUCCESS )\r
828         {\r
829             IotLogInfo( "(MQTT connection %p) Network connection closed.", pMqttConnection );\r
830         }\r
831         else\r
832         {\r
833             IotLogWarn( "(MQTT connection %p) Failed to close network connection, error %d.",\r
834                         pMqttConnection,\r
835                         closeStatus );\r
836         }\r
837     }\r
838     else\r
839     {\r
840         IotLogWarn( "(MQTT connection %p) No network close function was set. Network connection"\r
841                     " not closed.", pMqttConnection );\r
842     }\r
843 \r
844     /* Invoke the disconnect callback. */\r
845     if( pMqttConnection->disconnectCallback.function != NULL )\r
846     {\r
847         /* Set the members of the callback parameter. */\r
848         callbackParam.mqttConnection = pMqttConnection;\r
849         callbackParam.u.disconnectReason = disconnectReason;\r
850 \r
851         pMqttConnection->disconnectCallback.function( pMqttConnection->disconnectCallback.pCallbackContext,\r
852                                                       &callbackParam );\r
853     }\r
854     else\r
855     {\r
856         EMPTY_ELSE_MARKER;\r
857     }\r
858 }\r
859 \r
860 /*-----------------------------------------------------------*/\r
861 \r
862 void IotMqtt_ReceiveCallback( void * pNetworkConnection,\r
863                               void * pReceiveContext )\r
864 {\r
865     IotMqttError_t status = IOT_MQTT_SUCCESS;\r
866     _mqttPacket_t incomingPacket = { .u.pMqttConnection = NULL };\r
867 \r
868     /* Cast context to correct type. */\r
869     _mqttConnection_t * pMqttConnection = ( _mqttConnection_t * ) pReceiveContext;\r
870 \r
871     /* Read an MQTT packet from the network. */\r
872     status = _getIncomingPacket( pNetworkConnection,\r
873                                  pMqttConnection,\r
874                                  &incomingPacket );\r
875 \r
876     if( status == IOT_MQTT_SUCCESS )\r
877     {\r
878         /* Deserialize the received packet. */\r
879         status = _deserializeIncomingPacket( pMqttConnection,\r
880                                              &incomingPacket );\r
881 \r
882         /* Free any buffers allocated for the MQTT packet. */\r
883         if( incomingPacket.pRemainingData != NULL )\r
884         {\r
885             IotMqtt_FreeMessage( incomingPacket.pRemainingData );\r
886         }\r
887         else\r
888         {\r
889             EMPTY_ELSE_MARKER;\r
890         }\r
891     }\r
892     else\r
893     {\r
894         EMPTY_ELSE_MARKER;\r
895     }\r
896 \r
897     /* Close the network connection on a bad response. */\r
898     if( status == IOT_MQTT_BAD_RESPONSE )\r
899     {\r
900         IotLogError( "(MQTT connection %p) Error processing incoming data. Closing connection.",\r
901                      pMqttConnection );\r
902 \r
903         _IotMqtt_CloseNetworkConnection( IOT_MQTT_BAD_PACKET_RECEIVED,\r
904                                          pMqttConnection );\r
905     }\r
906     else\r
907     {\r
908         EMPTY_ELSE_MARKER;\r
909     }\r
910 }\r
911 \r
912 /*-----------------------------------------------------------*/\r