]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-IoT-SDK/abstractions/platform/freertos/iot_network_freertos.c
Add first draft of mqtt example
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-IoT-SDK / abstractions / platform / freertos / iot_network_freertos.c
1 /*\r
2  * Amazon FreeRTOS Platform V1.0.0\r
3  * Copyright (C) 2019 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_network_freertos.c\r
28  * @brief Implementation of the network-related functions from iot_network_freertos.h\r
29  * for Amazon FreeRTOS secure sockets.\r
30  */\r
31 \r
32 /* The config header is always included first. */\r
33 #include "iot_config.h"\r
34 \r
35 /* Standard includes. */\r
36 #include <string.h>\r
37 \r
38 /* FreeRTOS includes. */\r
39 #include "semphr.h"\r
40 #include "event_groups.h"\r
41 \r
42 /* Error handling include. */\r
43 #include "private/iot_error.h"\r
44 \r
45 /* Amazon FreeRTOS network include. */\r
46 #include "platform/iot_network_freertos.h"\r
47 \r
48 /* Configure logs for the functions in this file. */\r
49 #ifdef IOT_LOG_LEVEL_NETWORK\r
50     #define LIBRARY_LOG_LEVEL        IOT_LOG_LEVEL_NETWORK\r
51 #else\r
52     #ifdef IOT_LOG_LEVEL_GLOBAL\r
53         #define LIBRARY_LOG_LEVEL    IOT_LOG_LEVEL_GLOBAL\r
54     #else\r
55         #define LIBRARY_LOG_LEVEL    IOT_LOG_NONE\r
56     #endif\r
57 #endif\r
58 \r
59 #define LIBRARY_LOG_NAME    ( "NET" )\r
60 #include "iot_logging_setup.h"\r
61 \r
62 /* Provide a default value for the number of milliseconds for a socket poll.\r
63  * This is a temporary workaround to deal with the lack of poll(). */\r
64 #ifndef IOT_NETWORK_SOCKET_POLL_MS\r
65     #define IOT_NETWORK_SOCKET_POLL_MS    ( 1000 )\r
66 #endif\r
67 \r
68 /**\r
69  * @brief The event group bit to set when a connection's socket is shut down.\r
70  */\r
71 #define _FLAG_SHUTDOWN                ( 1 )\r
72 \r
73 /**\r
74  * @brief The event group bit to set when a connection's receive task exits.\r
75  */\r
76 #define _FLAG_RECEIVE_TASK_EXITED     ( 2 )\r
77 \r
78 /**\r
79  * @brief The event group bit to set when the connection is destroyed from the\r
80  * receive task.\r
81  */\r
82 #define _FLAG_CONNECTION_DESTROYED    ( 4 )\r
83 \r
84 /*-----------------------------------------------------------*/\r
85 \r
86 typedef struct _networkConnection\r
87 {\r
88     Socket_t socket;                             /**< @brief Amazon FreeRTOS Secure Sockets handle. */\r
89     StaticSemaphore_t socketMutex;               /**< @brief Prevents concurrent threads from sending on a socket. */\r
90     StaticEventGroup_t connectionFlags;          /**< @brief Synchronizes with the receive task. */\r
91     TaskHandle_t receiveTask;                    /**< @brief Handle of the receive task, if any. */\r
92     IotNetworkReceiveCallback_t receiveCallback; /**< @brief Network receive callback, if any. */\r
93     void * pReceiveContext;                      /**< @brief The context for the receive callback. */\r
94     bool bufferedByteValid;                      /**< @brief Used to determine if the buffered byte is valid. */\r
95     uint8_t bufferedByte;                        /**< @brief A single byte buffered from a receive, since AFR Secure Sockets does not have poll(). */\r
96 } _networkConnection_t;\r
97 \r
98 /*-----------------------------------------------------------*/\r
99 \r
100 /**\r
101  * @brief An #IotNetworkInterface_t that uses the functions in this file.\r
102  */\r
103 const IotNetworkInterface_t IotNetworkAfr =\r
104 {\r
105     .create             = IotNetworkAfr_Create,\r
106     .setReceiveCallback = IotNetworkAfr_SetReceiveCallback,\r
107     .send               = IotNetworkAfr_Send,\r
108     .receive            = IotNetworkAfr_Receive,\r
109     .close              = IotNetworkAfr_Close,\r
110     .destroy            = IotNetworkAfr_Destroy\r
111 };\r
112 \r
113 /*-----------------------------------------------------------*/\r
114 \r
115 /**\r
116  * @brief Destroys a network connection.\r
117  *\r
118  * @param[in] pNetworkConnection The connection to destroy.\r
119  */\r
120 static void _destroyConnection( _networkConnection_t * pNetworkConnection )\r
121 {\r
122     /* Call Secure Sockets close function to free resources. */\r
123     int32_t socketStatus = SOCKETS_Close( pNetworkConnection->socket );\r
124 \r
125     if( socketStatus != SOCKETS_ERROR_NONE )\r
126     {\r
127         IotLogWarn( "Failed to destroy connection." );\r
128     }\r
129 \r
130     /* Free the network connection. */\r
131     vPortFree( pNetworkConnection );\r
132 }\r
133 \r
134 /*-----------------------------------------------------------*/\r
135 \r
136 /**\r
137  * @brief Task routine that waits on incoming network data.\r
138  *\r
139  * @param[in] pArgument The network connection.\r
140  */\r
141 static void _networkReceiveTask( void * pArgument )\r
142 {\r
143     bool destroyConnection = false;\r
144     int32_t socketStatus = 0;\r
145     EventBits_t connectionFlags = 0;\r
146 \r
147     /* Cast network connection to the correct type. */\r
148     _networkConnection_t * pNetworkConnection = pArgument;\r
149 \r
150     while( true )\r
151     {\r
152         /* No buffered byte should be in the connection. */\r
153         configASSERT( pNetworkConnection->bufferedByteValid == false );\r
154 \r
155         /* Block and wait for 1 byte of data. This simulates the behavior of poll().\r
156          * THIS IS A TEMPORARY WORKAROUND AND DOES NOT PROVIDE THREAD-SAFETY AGAINST\r
157          * MULTIPLE CALLS OF RECEIVE. */\r
158         do\r
159         {\r
160             socketStatus = SOCKETS_Recv( pNetworkConnection->socket,\r
161                                          &( pNetworkConnection->bufferedByte ),\r
162                                          1,\r
163                                          0 );\r
164 \r
165             connectionFlags = xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) );\r
166 \r
167             if( ( connectionFlags & _FLAG_SHUTDOWN ) == _FLAG_SHUTDOWN )\r
168             {\r
169                 socketStatus = SOCKETS_ECLOSED;\r
170             }\r
171 \r
172             /* Check for timeout. Some ports return 0, some return EWOULDBLOCK. */\r
173         } while( ( socketStatus == 0 ) || ( socketStatus == SOCKETS_EWOULDBLOCK ) );\r
174 \r
175         if( socketStatus <= 0 )\r
176         {\r
177             break;\r
178         }\r
179 \r
180         pNetworkConnection->bufferedByteValid = true;\r
181 \r
182         /* Invoke the network callback. */\r
183         pNetworkConnection->receiveCallback( pNetworkConnection,\r
184                                              pNetworkConnection->pReceiveContext );\r
185 \r
186         /* Check if the connection was destroyed by the receive callback. This\r
187          * does not need to be thread-safe because the destroy connection function\r
188          * may only be called once (per its API doc). */\r
189         connectionFlags = xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) );\r
190 \r
191         if( ( connectionFlags & _FLAG_CONNECTION_DESTROYED ) == _FLAG_CONNECTION_DESTROYED )\r
192         {\r
193             destroyConnection = true;\r
194             break;\r
195         }\r
196     }\r
197 \r
198     IotLogDebug( "Network receive task terminating." );\r
199 \r
200     /* If necessary, destroy the network connection before exiting. */\r
201     if( destroyConnection == true )\r
202     {\r
203         _destroyConnection( pNetworkConnection );\r
204     }\r
205     else\r
206     {\r
207         /* Set the flag to indicate that the receive task has exited. */\r
208         ( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),\r
209                                      _FLAG_RECEIVE_TASK_EXITED );\r
210     }\r
211 \r
212     vTaskDelete( NULL );\r
213 }\r
214 \r
215 /*-----------------------------------------------------------*/\r
216 \r
217 /**\r
218  * @brief Set up a secured TLS connection.\r
219  *\r
220  * @param[in] pAfrCredentials Credentials for the secured connection.\r
221  * @param[in] tcpSocket An initialized socket to secure.\r
222  * @param[in] pHostName Remote server name for SNI.\r
223  * @param[in] hostnameLength The length of `pHostName`.\r
224  *\r
225  * @return #IOT_NETWORK_SUCCESS or #IOT_NETWORK_SYSTEM_ERROR.\r
226  */\r
227 static IotNetworkError_t _tlsSetup( const IotNetworkCredentials_t * pAfrCredentials,\r
228                                     Socket_t tcpSocket,\r
229                                     const char * pHostName,\r
230                                     size_t hostnameLength )\r
231 {\r
232     IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );\r
233     int32_t socketStatus = SOCKETS_ERROR_NONE;\r
234 \r
235     /* ALPN options for AWS IoT. */\r
236     const char * ppcALPNProtos[] = { socketsAWS_IOT_ALPN_MQTT };\r
237 \r
238     /* Set secured option. */\r
239     socketStatus = SOCKETS_SetSockOpt( tcpSocket,\r
240                                        0,\r
241                                        SOCKETS_SO_REQUIRE_TLS,\r
242                                        NULL,\r
243                                        0 );\r
244 \r
245     if( socketStatus != SOCKETS_ERROR_NONE )\r
246     {\r
247         IotLogError( "Failed to set secured option for new connection." );\r
248         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
249     }\r
250 \r
251     /* Set ALPN option. */\r
252     if( pAfrCredentials->pAlpnProtos != NULL )\r
253     {\r
254         socketStatus = SOCKETS_SetSockOpt( tcpSocket,\r
255                                            0,\r
256                                            SOCKETS_SO_ALPN_PROTOCOLS,\r
257                                            ppcALPNProtos,\r
258                                            sizeof( ppcALPNProtos ) / sizeof( ppcALPNProtos[ 0 ] ) );\r
259 \r
260         if( socketStatus != SOCKETS_ERROR_NONE )\r
261         {\r
262             IotLogError( "Failed to set ALPN option for new connection." );\r
263             IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
264         }\r
265     }\r
266 \r
267     /* Set SNI option. */\r
268     if( pAfrCredentials->disableSni == false )\r
269     {\r
270         socketStatus = SOCKETS_SetSockOpt( tcpSocket,\r
271                                            0,\r
272                                            SOCKETS_SO_SERVER_NAME_INDICATION,\r
273                                            pHostName,\r
274                                            hostnameLength + 1 );\r
275 \r
276         if( socketStatus != SOCKETS_ERROR_NONE )\r
277         {\r
278             IotLogError( "Failed to set SNI option for new connection." );\r
279             IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
280         }\r
281     }\r
282 \r
283     /* Set custom server certificate. */\r
284     if( pAfrCredentials->pRootCa != NULL )\r
285     {\r
286         socketStatus = SOCKETS_SetSockOpt( tcpSocket,\r
287                                            0,\r
288                                            SOCKETS_SO_TRUSTED_SERVER_CERTIFICATE,\r
289                                            pAfrCredentials->pRootCa,\r
290                                            pAfrCredentials->rootCaSize );\r
291 \r
292         if( socketStatus != SOCKETS_ERROR_NONE )\r
293         {\r
294             IotLogError( "Failed to set server certificate option for new connection." );\r
295             IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
296         }\r
297     }\r
298 \r
299     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
300 }\r
301 \r
302 /*-----------------------------------------------------------*/\r
303 \r
304 IotNetworkError_t IotNetworkAfr_Create( void * pConnectionInfo,\r
305                                         void * pCredentialInfo,\r
306                                         void ** pConnection )\r
307 {\r
308     IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );\r
309     Socket_t tcpSocket = SOCKETS_INVALID_SOCKET;\r
310     int32_t socketStatus = SOCKETS_ERROR_NONE;\r
311     SocketsSockaddr_t serverAddress = { 0 };\r
312     EventGroupHandle_t pConnectionFlags = NULL;\r
313     SemaphoreHandle_t pConnectionMutex = NULL;\r
314     const TickType_t receiveTimeout = pdMS_TO_TICKS( IOT_NETWORK_SOCKET_POLL_MS );\r
315     _networkConnection_t * pNewNetworkConnection = NULL;\r
316 \r
317     /* Cast function parameters to correct types. */\r
318     const IotNetworkServerInfo_t * pServerInfo = pConnectionInfo;\r
319     const IotNetworkCredentials_t * pAfrCredentials = pCredentialInfo;\r
320     _networkConnection_t ** pNetworkConnection = ( _networkConnection_t ** ) pConnection;\r
321 \r
322     /* Check host name length against the maximum length allowed by Secure\r
323      * Sockets. */\r
324     const size_t hostnameLength = strlen( pServerInfo->pHostName );\r
325 \r
326     if( hostnameLength > ( size_t ) securesocketsMAX_DNS_NAME_LENGTH )\r
327     {\r
328         IotLogError( "Host name length exceeds %d, which is the maximum allowed.",\r
329                      securesocketsMAX_DNS_NAME_LENGTH );\r
330         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_BAD_PARAMETER );\r
331     }\r
332 \r
333     pNewNetworkConnection = pvPortMalloc( sizeof( _networkConnection_t ) );\r
334 \r
335     if( pNewNetworkConnection == NULL )\r
336     {\r
337         IotLogError( "Failed to allocate memory for new network connection." );\r
338         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );\r
339     }\r
340 \r
341     /* Clear the connection information. */\r
342     ( void ) memset( pNewNetworkConnection, 0x00, sizeof( _networkConnection_t ) );\r
343 \r
344     /* Create a new TCP socket. */\r
345     tcpSocket = SOCKETS_Socket( SOCKETS_AF_INET,\r
346                                 SOCKETS_SOCK_STREAM,\r
347                                 SOCKETS_IPPROTO_TCP );\r
348 \r
349     if( tcpSocket == SOCKETS_INVALID_SOCKET )\r
350     {\r
351         IotLogError( "Failed to create new socket." );\r
352         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
353     }\r
354 \r
355     /* Set up connection encryption if credentials are provided. */\r
356     if( pAfrCredentials != NULL )\r
357     {\r
358         status = _tlsSetup( pAfrCredentials, tcpSocket, pServerInfo->pHostName, hostnameLength );\r
359 \r
360         if( status != IOT_NETWORK_SUCCESS )\r
361         {\r
362             IOT_GOTO_CLEANUP();\r
363         }\r
364     }\r
365 \r
366     /* Establish connection. */\r
367     serverAddress.ucSocketDomain = SOCKETS_AF_INET;\r
368     serverAddress.usPort = SOCKETS_htons( pServerInfo->port );\r
369     serverAddress.ulAddress = SOCKETS_GetHostByName( pServerInfo->pHostName );\r
370 \r
371     /* Check for errors from DNS lookup. */\r
372     if( serverAddress.ulAddress == 0 )\r
373     {\r
374         IotLogError( "Failed to resolve %s.", pServerInfo->pHostName );\r
375         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
376     }\r
377 \r
378     socketStatus = SOCKETS_Connect( tcpSocket,\r
379                                     &serverAddress,\r
380                                     sizeof( SocketsSockaddr_t ) );\r
381 \r
382     if( socketStatus != SOCKETS_ERROR_NONE )\r
383     {\r
384         IotLogError( "Failed to establish new connection." );\r
385         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
386     }\r
387 \r
388     /* Set a long timeout for receive. */\r
389     socketStatus = SOCKETS_SetSockOpt( tcpSocket,\r
390                                        0,\r
391                                        SOCKETS_SO_RCVTIMEO,\r
392                                        &receiveTimeout,\r
393                                        sizeof( TickType_t ) );\r
394 \r
395     if( socketStatus != SOCKETS_ERROR_NONE )\r
396     {\r
397         IotLogError( "Failed to set socket receive timeout." );\r
398         IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
399     }\r
400 \r
401     IOT_FUNCTION_CLEANUP_BEGIN();\r
402 \r
403     /* Clean up on failure. */\r
404     if( status != IOT_NETWORK_SUCCESS )\r
405     {\r
406         if( tcpSocket != SOCKETS_INVALID_SOCKET )\r
407         {\r
408             SOCKETS_Close( tcpSocket );\r
409         }\r
410 \r
411         /* Clear the connection information. */\r
412         if( pNewNetworkConnection != NULL )\r
413         {\r
414             vPortFree( pNewNetworkConnection );\r
415         }\r
416     }\r
417     else\r
418     {\r
419         /* Set the socket. */\r
420         pNewNetworkConnection->socket = tcpSocket;\r
421 \r
422         /* Create the connection event flags and mutex. */\r
423         pConnectionFlags = xEventGroupCreateStatic( &( pNewNetworkConnection->connectionFlags ) );\r
424         pConnectionMutex = xSemaphoreCreateMutexStatic( &( pNewNetworkConnection->socketMutex ) );\r
425 \r
426         /* Static event flags and mutex creation should never fail. The handles\r
427          * should point inside the connection object. */\r
428         configASSERT( pConnectionFlags == ( EventGroupHandle_t ) &( pNewNetworkConnection->connectionFlags ) );\r
429         configASSERT( pConnectionMutex == ( SemaphoreHandle_t ) &( pNewNetworkConnection->socketMutex ) );\r
430 \r
431         /* Set the output parameter. */\r
432         *pNetworkConnection = pNewNetworkConnection;\r
433     }\r
434 \r
435     IOT_FUNCTION_CLEANUP_END();\r
436 }\r
437 \r
438 /*-----------------------------------------------------------*/\r
439 \r
440 IotNetworkError_t IotNetworkAfr_SetReceiveCallback( void * pConnection,\r
441                                                     IotNetworkReceiveCallback_t receiveCallback,\r
442                                                     void * pContext )\r
443 {\r
444     IotNetworkError_t status = IOT_NETWORK_SUCCESS;\r
445 \r
446     /* Cast network connection to the correct type. */\r
447     _networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;\r
448 \r
449     /* Set the receive callback and context. */\r
450     pNetworkConnection->receiveCallback = receiveCallback;\r
451     pNetworkConnection->pReceiveContext = pContext;\r
452 \r
453     /* No flags should be set. */\r
454     configASSERT( xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) ) == 0 );\r
455 \r
456     /* Create task that waits for incoming data. */\r
457     if( xTaskCreate( _networkReceiveTask,\r
458                      "NetRecv",\r
459                      IOT_NETWORK_RECEIVE_TASK_STACK_SIZE,\r
460                      pNetworkConnection,\r
461                      IOT_NETWORK_RECEIVE_TASK_PRIORITY,\r
462                      &( pNetworkConnection->receiveTask ) ) != pdPASS )\r
463     {\r
464         IotLogError( "Failed to create network receive task." );\r
465 \r
466         status = IOT_NETWORK_SYSTEM_ERROR;\r
467     }\r
468 \r
469     return status;\r
470 }\r
471 \r
472 /*-----------------------------------------------------------*/\r
473 \r
474 size_t IotNetworkAfr_Send( void * pConnection,\r
475                            const uint8_t * pMessage,\r
476                            size_t messageLength )\r
477 {\r
478     size_t bytesSent = 0;\r
479     int32_t socketStatus = SOCKETS_ERROR_NONE;\r
480 \r
481     /* Cast network connection to the correct type. */\r
482     _networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;\r
483 \r
484     /* Only one thread at a time may send on the connection. Lock the socket\r
485      * mutex to prevent other threads from sending. */\r
486     if( xSemaphoreTake( ( QueueHandle_t ) &( pNetworkConnection->socketMutex ),\r
487                         portMAX_DELAY ) == pdTRUE )\r
488     {\r
489         socketStatus = SOCKETS_Send( pNetworkConnection->socket,\r
490                                      pMessage,\r
491                                      messageLength,\r
492                                      0 );\r
493 \r
494         if( socketStatus > 0 )\r
495         {\r
496             bytesSent = ( size_t ) socketStatus;\r
497         }\r
498 \r
499         xSemaphoreGive( ( QueueHandle_t ) &( pNetworkConnection->socketMutex ) );\r
500     }\r
501 \r
502     return bytesSent;\r
503 }\r
504 \r
505 /*-----------------------------------------------------------*/\r
506 \r
507 size_t IotNetworkAfr_Receive( void * pConnection,\r
508                               uint8_t * pBuffer,\r
509                               size_t bytesRequested )\r
510 {\r
511     int32_t socketStatus = 0;\r
512     size_t bytesReceived = 0, bytesRemaining = bytesRequested;\r
513 \r
514     /* Cast network connection to the correct type. */\r
515     _networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;\r
516 \r
517     /* Write the buffered byte. THIS IS A TEMPORARY WORKAROUND AND ASSUMES THIS\r
518      * FUNCTION IS ALWAYS CALLED FROM THE RECEIVE CALLBACK. */\r
519     if( pNetworkConnection->bufferedByteValid == true )\r
520     {\r
521         *pBuffer = pNetworkConnection->bufferedByte;\r
522         bytesReceived = 1;\r
523         bytesRemaining--;\r
524         pNetworkConnection->bufferedByteValid = false;\r
525     }\r
526 \r
527     /* Block and wait for incoming data. */\r
528     while( bytesRemaining > 0 )\r
529     {\r
530         socketStatus = SOCKETS_Recv( pNetworkConnection->socket,\r
531                                      pBuffer + bytesReceived,\r
532                                      bytesRemaining,\r
533                                      0 );\r
534 \r
535         if( socketStatus == SOCKETS_EWOULDBLOCK )\r
536         {\r
537             /* The return value EWOULDBLOCK means no data was received within\r
538              * the socket timeout. Ignore it and try again. */\r
539             continue;\r
540         }\r
541         else if( socketStatus <= 0 )\r
542         {\r
543             IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus );\r
544             break;\r
545         }\r
546         else\r
547         {\r
548             bytesReceived += ( size_t ) socketStatus;\r
549             bytesRemaining -= ( size_t ) socketStatus;\r
550 \r
551             configASSERT( bytesReceived + bytesRemaining == bytesRequested );\r
552         }\r
553     }\r
554 \r
555     if( bytesReceived < bytesRequested )\r
556     {\r
557         IotLogWarn( "Receive requested %lu bytes, but %lu bytes received instead.",\r
558                     ( unsigned long ) bytesRequested,\r
559                     ( unsigned long ) bytesReceived );\r
560     }\r
561     else\r
562     {\r
563         IotLogDebug( "Successfully received %lu bytes.",\r
564                      ( unsigned long ) bytesRequested );\r
565     }\r
566 \r
567     return bytesReceived;\r
568 }\r
569 \r
570 /*-----------------------------------------------------------*/\r
571 \r
572 IotNetworkError_t IotNetworkAfr_Close( void * pConnection )\r
573 {\r
574     int32_t socketStatus = SOCKETS_ERROR_NONE;\r
575 \r
576     /* Cast network connection to the correct type. */\r
577     _networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;\r
578 \r
579     /* Call Secure Sockets shutdown function to close connection. */\r
580     socketStatus = SOCKETS_Shutdown( pNetworkConnection->socket,\r
581                                      SOCKETS_SHUT_RDWR );\r
582 \r
583     if( socketStatus != SOCKETS_ERROR_NONE )\r
584     {\r
585         IotLogWarn( "Failed to close connection." );\r
586     }\r
587 \r
588     /* Set the shutdown flag. */\r
589     ( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),\r
590                                  _FLAG_SHUTDOWN );\r
591 \r
592     return IOT_NETWORK_SUCCESS;\r
593 }\r
594 \r
595 /*-----------------------------------------------------------*/\r
596 \r
597 IotNetworkError_t IotNetworkAfr_Destroy( void * pConnection )\r
598 {\r
599     /* Cast network connection to the correct type. */\r
600     _networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;\r
601 \r
602     /* Check if this function is being called from the receive task. */\r
603     if( xTaskGetCurrentTaskHandle() == pNetworkConnection->receiveTask )\r
604     {\r
605         /* Set the flag specifying that the connection is destroyed. */\r
606         ( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),\r
607                                      _FLAG_CONNECTION_DESTROYED );\r
608     }\r
609     else\r
610     {\r
611         /* If a receive task was created, wait for it to exit. */\r
612         if( pNetworkConnection->receiveTask != NULL )\r
613         {\r
614             ( void ) xEventGroupWaitBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),\r
615                                           _FLAG_RECEIVE_TASK_EXITED,\r
616                                           pdTRUE,\r
617                                           pdTRUE,\r
618                                           portMAX_DELAY );\r
619         }\r
620 \r
621         _destroyConnection( pNetworkConnection );\r
622     }\r
623 \r
624     return IOT_NETWORK_SUCCESS;\r
625 }\r
626 \r
627 /*-----------------------------------------------------------*/\r