]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-IoT-Libraries / abstractions / platform / freertos / iot_network_freertos.c
diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c
new file mode 100644 (file)
index 0000000..50ea1df
--- /dev/null
@@ -0,0 +1,968 @@
+/*\r
+ * Amazon FreeRTOS Platform V1.1.0\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://aws.amazon.com/freertos\r
+ * http://www.FreeRTOS.org\r
+ */\r
+\r
+/**\r
+ * @file iot_network_freertos.c\r
+ * @brief Implementation of the network-related functions from iot_network_freertos.h\r
+ * for FreeRTOS+TCP sockets.\r
+ */\r
+\r
+/* The config header is always included first. */\r
+#include "iot_config.h"\r
+\r
+/* Standard includes. */\r
+#include <string.h>\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "atomic.h"\r
+#include "semphr.h"\r
+\r
+/* FreeRTOS+TCP includes. */\r
+#include "FreeRTOS_IP.h"\r
+#include "FreeRTOS_Sockets.h"\r
+\r
+/* FreeRTOS-IoT-Libraries includes. */\r
+#include "iot_error.h"\r
+#include "platform/iot_network_freertos.h"\r
+\r
+#if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+    /* mbed TLS includes. */\r
+    #include "mbedtls/ctr_drbg.h"\r
+    #include "mbedtls/entropy.h"\r
+    #include "mbedtls/ssl.h"\r
+    #include "mbedtls/threading.h"\r
+    #include "mbedtls/x509.h"\r
+#endif\r
+\r
+/* Configure logs for the functions in this file. */\r
+#ifdef IOT_LOG_LEVEL_NETWORK\r
+    #define LIBRARY_LOG_LEVEL        IOT_LOG_LEVEL_NETWORK\r
+#else\r
+    #ifdef IOT_LOG_LEVEL_GLOBAL\r
+        #define LIBRARY_LOG_LEVEL    IOT_LOG_LEVEL_GLOBAL\r
+    #else\r
+        #define LIBRARY_LOG_LEVEL    IOT_LOG_NONE\r
+    #endif\r
+#endif\r
+\r
+#define LIBRARY_LOG_NAME    ( "NET" )\r
+#include "iot_logging_setup.h"\r
+\r
+/* Provide a default value for socket timeout and network task parameters. */\r
+#ifndef IOT_NETWORK_SOCKET_TIMEOUT_MS\r
+    #define IOT_NETWORK_SOCKET_TIMEOUT_MS    ( 5000 )\r
+#endif\r
+#ifndef IOT_NETWORK_TASK_STACK_SIZE\r
+    #define IOT_NETWORK_TASK_STACK_SIZE      ( 2048 )\r
+#endif\r
+#ifndef IOT_NETWORK_TASK_PRIORITY\r
+    #define IOT_NETWORK_TASK_PRIORITY        ( tskIDLE_PRIORITY )\r
+#endif\r
+\r
+/* Maximum number of simultaneous socket receive callbacks. */\r
+#ifndef IOT_NETWORK_MAX_RECEIVE_CALLBACKS\r
+    #define IOT_NETWORK_MAX_RECEIVE_CALLBACKS    ( 2 )\r
+#endif\r
+\r
+/**\r
+ * @brief Maximum length of a DNS name.\r
+ *\r
+ * Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length\r
+ * of a DNS name.\r
+ */\r
+#define MAX_DNS_NAME_LENGTH    ( 253 )\r
+/*-----------------------------------------------------------*/\r
+\r
+/**\r
+ * @brief Internal network context.\r
+ */\r
+typedef struct _networkConnection\r
+{\r
+    Socket_t socket;                             /**< @brief FreeRTOS+TCP sockets handle. */\r
+    SemaphoreHandle_t socketMutex;               /**< @brief Prevents concurrent threads from using a socket. */\r
+    StaticSemaphore_t socketMutexStorage;        /**< @brief Storage space for socketMutex. */\r
+    IotNetworkReceiveCallback_t receiveCallback; /**< @brief Network receive callback, if any. */\r
+    void * pReceiveContext;                      /**< @brief The context for the receive callback. */\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        BaseType_t secured; /**< @brief Flag that marks a connection as secured. */\r
+\r
+        /**\r
+         * @brief Secured connection context. Valid if `secured` is `pdTRUE`.\r
+         */\r
+        struct\r
+        {\r
+            mbedtls_ssl_config config;            /**< @brief SSL connection configuration. */\r
+            mbedtls_ssl_context context;          /**< @brief SSL connection context */\r
+            mbedtls_x509_crt_profile certProfile; /**< @brief Certificate security profile for this connection. */\r
+            mbedtls_x509_crt rootCa;              /**< @brief Root CA certificate context. */\r
+            mbedtls_x509_crt clientCert;          /**< @brief Client certificate context. */\r
+            mbedtls_pk_context privKey;           /**< @brief Client private key context. */\r
+        } ssl;\r
+    #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+} _networkConnection_t;\r
+/*-----------------------------------------------------------*/\r
+\r
+#if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+\r
+/**\r
+ * @brief mbed TLS entropy context for generation of random numbers.\r
+ */\r
+    static mbedtls_entropy_context _entropyContext;\r
+\r
+/**\r
+ * @brief mbed TLS CTR DRBG context for generation of random numbers.\r
+ */\r
+    static mbedtls_ctr_drbg_context _ctrDrgbContext;\r
+#endif\r
+\r
+/**\r
+ * @brief Handle of the network task.\r
+ */\r
+static TaskHandle_t _networkTaskHandle;\r
+\r
+/**\r
+ * @brief Socket set for the network task.\r
+ */\r
+static SocketSet_t _socketSet;\r
+\r
+/**\r
+ * @brief Connections in _socketSet.\r
+ */\r
+static _networkConnection_t * _connections[ IOT_NETWORK_MAX_RECEIVE_CALLBACKS ];\r
+\r
+/**\r
+ * @brief An #IotNetworkInterface_t that uses the functions in this file.\r
+ */\r
+const IotNetworkInterface_t IotNetworkFreeRTOS =\r
+{\r
+    .create             = IotNetworkFreeRTOS_Create,\r
+    .setReceiveCallback = IotNetworkFreeRTOS_SetReceiveCallback,\r
+    .send               = IotNetworkFreeRTOS_Send,\r
+    .receive            = IotNetworkFreeRTOS_Receive,\r
+    .receiveUpto        = IotNetworkFreeRTOS_ReceiveUpto,\r
+    .close              = IotNetworkFreeRTOS_Close,\r
+    .destroy            = IotNetworkFreeRTOS_Destroy\r
+};\r
+/*-----------------------------------------------------------*/\r
+\r
+#if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+\r
+/**\r
+ * @brief Initialize the mbed TLS structures in a network connection.\r
+ *\r
+ * @param[in] pNetworkConnection The network connection to initialize.\r
+ */\r
+    static void _sslContextInit( _networkConnection_t * pNetworkConnection )\r
+    {\r
+        mbedtls_ssl_config_init( &( pNetworkConnection->ssl.config ) );\r
+        mbedtls_x509_crt_init( &( pNetworkConnection->ssl.rootCa ) );\r
+        mbedtls_pk_init( &( pNetworkConnection->ssl.privKey ) );\r
+        mbedtls_x509_crt_init( &( pNetworkConnection->ssl.clientCert ) );\r
+        mbedtls_ssl_init( &( pNetworkConnection->ssl.context ) );\r
+    }\r
+/*-----------------------------------------------------------*/\r
+\r
+/**\r
+ * @brief Free the mbed TLS structures in a network connection.\r
+ *\r
+ * @param[in] pNetworkConnection The network connection with the contexts to free.\r
+ */\r
+    static void _sslContextFree( _networkConnection_t * pNetworkConnection )\r
+    {\r
+        mbedtls_ssl_free( &( pNetworkConnection->ssl.context ) );\r
+        mbedtls_x509_crt_free( &( pNetworkConnection->ssl.rootCa ) );\r
+        mbedtls_x509_crt_free( &( pNetworkConnection->ssl.clientCert ) );\r
+        mbedtls_pk_free( &( pNetworkConnection->ssl.privKey ) );\r
+        mbedtls_ssl_config_free( &( pNetworkConnection->ssl.config ) );\r
+    }\r
+/*-----------------------------------------------------------*/\r
+\r
+/**\r
+ * @brief Set up TLS on a TCP connection.\r
+ *\r
+ * @param[in] pNetworkConnection An established TCP connection.\r
+ * @param[in] pServerName Remote host name, used for server name indication.\r
+ * @param[in] pCredentials TLS setup parameters.\r
+ *\r
+ * @return #IOT_NETWORK_SUCCESS, #IOT_NETWORK_FAILURE, #IOT_NETWORK_NO_MEMORY,\r
+ * or #IOT_NETWORK_SYSTEM_ERROR.\r
+ */\r
+    static IotNetworkError_t _tlsSetup( _networkConnection_t * pNetworkConnection,\r
+                                        const char * pServerName,\r
+                                        IotNetworkCredentials_t pCredentials )\r
+    {\r
+        IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );\r
+        int mbedtlsError = 0;\r
+\r
+        /* Initialize the mbed TLS context structures. */\r
+        _sslContextInit( pNetworkConnection );\r
+\r
+        mbedtlsError = mbedtls_ssl_config_defaults( &( pNetworkConnection->ssl.config ),\r
+                                                    MBEDTLS_SSL_IS_CLIENT,\r
+                                                    MBEDTLS_SSL_TRANSPORT_STREAM,\r
+                                                    MBEDTLS_SSL_PRESET_DEFAULT );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to set default SSL configuration, error %d.", mbedtlsError );\r
+\r
+            /* Per mbed TLS docs, mbedtls_ssl_config_defaults only fails on memory allocation. */\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );\r
+        }\r
+\r
+        /* Set up the certificate security profile, starting from the default value. */\r
+        pNetworkConnection->ssl.certProfile = mbedtls_x509_crt_profile_default;\r
+\r
+        /* test.mosquitto.org only provides a 1024-bit RSA certificate, which is\r
+         * not acceptable by the default mbed TLS certificate security profile.\r
+         * For the purposes of this demo, allow the use of 1024-bit RSA certificates.\r
+         * This block should be removed otherwise. */\r
+        if( strncmp( pServerName, "test.mosquitto.org", strlen( pServerName ) ) == 0 )\r
+        {\r
+            pNetworkConnection->ssl.certProfile.rsa_min_bitlen = 1024;\r
+        }\r
+\r
+        /* Set SSL authmode and the RNG context. */\r
+        mbedtls_ssl_conf_authmode( &( pNetworkConnection->ssl.config ),\r
+                                   MBEDTLS_SSL_VERIFY_REQUIRED );\r
+        mbedtls_ssl_conf_rng( &( pNetworkConnection->ssl.config ),\r
+                              mbedtls_ctr_drbg_random,\r
+                              &_ctrDrgbContext );\r
+        mbedtls_ssl_conf_cert_profile( &( pNetworkConnection->ssl.config ),\r
+                                       &( pNetworkConnection->ssl.certProfile ) );\r
+\r
+        /* Parse the server root CA certificate into the SSL context. */\r
+        mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.rootCa ),\r
+                                               ( const unsigned char * ) pCredentials->pRootCa,\r
+                                               pCredentials->rootCaSize );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to parse server root CA certificate, error %d.",\r
+                         mbedtlsError );\r
+\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+        }\r
+\r
+        mbedtls_ssl_conf_ca_chain( &( pNetworkConnection->ssl.config ),\r
+                                   &( pNetworkConnection->ssl.rootCa ),\r
+                                   NULL );\r
+\r
+        if( ( pCredentials->pPrivateKey != NULL ) && ( pCredentials->pClientCert != NULL ) )\r
+        {\r
+            /* Setup the client private key. */\r
+            mbedtlsError = mbedtls_pk_parse_key( &( pNetworkConnection->ssl.privKey ),\r
+                                                 ( const unsigned char * ) pCredentials->pPrivateKey,\r
+                                                 pCredentials->privateKeySize,\r
+                                                 0,\r
+                                                 0 );\r
+\r
+            if( mbedtlsError != 0 )\r
+            {\r
+                IotLogError( "Failed to parse client certificate, error %d.",\r
+                             mbedtlsError );\r
+\r
+                IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+            }\r
+\r
+            /* Setup the client certificate. */\r
+            mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.clientCert ),\r
+                                                   ( const unsigned char * ) pCredentials->pClientCert,\r
+                                                   pCredentials->clientCertSize );\r
+\r
+            if( mbedtlsError != 0 )\r
+            {\r
+                IotLogError( "Failed to parse the client private key, error %d.",\r
+                             mbedtlsError );\r
+\r
+                IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+            }\r
+\r
+            mbedtls_ssl_conf_own_cert( &( pNetworkConnection->ssl.config ),\r
+                                       &( pNetworkConnection->ssl.clientCert ),\r
+                                       &( pNetworkConnection->ssl.privKey ) );\r
+        }\r
+\r
+        /* Initialize the mbed TLS secured connection context. */\r
+        mbedtlsError = mbedtls_ssl_setup( &( pNetworkConnection->ssl.context ),\r
+                                          &( pNetworkConnection->ssl.config ) );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to set up mbed TLS SSL context, error %d.",\r
+                         mbedtlsError );\r
+\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+        }\r
+\r
+        /* Set the underlying IO for the TLS connection. */\r
+        mbedtls_ssl_set_bio( &( pNetworkConnection->ssl.context ),\r
+                             pNetworkConnection->socket,\r
+                             mbedtls_platform_send,\r
+                             mbedtls_platform_recv,\r
+                             NULL );\r
+\r
+        /* Enable SNI if requested. */\r
+        if( pCredentials->disableSni == false )\r
+        {\r
+            mbedtlsError = mbedtls_ssl_set_hostname( &( pNetworkConnection->ssl.context ),\r
+                                                     pServerName );\r
+\r
+            if( mbedtlsError != 0 )\r
+            {\r
+                IotLogError( "Failed to set server name, error %d.", mbedtlsError );\r
+\r
+                IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+            }\r
+        }\r
+\r
+        /* Perform the TLS handshake. */\r
+        do\r
+        {\r
+            mbedtlsError = mbedtls_ssl_handshake( &( pNetworkConnection->ssl.context ) );\r
+        } while( ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_READ ) ||\r
+                 ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_WRITE ) );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to perform TLS handshake, error %d.", mbedtlsError );\r
+\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );\r
+        }\r
+\r
+        /* Clean up on error. */\r
+        IOT_FUNCTION_CLEANUP_BEGIN();\r
+\r
+        if( status != IOT_NETWORK_SUCCESS )\r
+        {\r
+            _sslContextFree( pNetworkConnection );\r
+        }\r
+        else\r
+        {\r
+            pNetworkConnection->secured = pdTRUE;\r
+\r
+            IotLogInfo( "(Network connection %p) TLS handshake successful.",\r
+                        pNetworkConnection );\r
+        }\r
+\r
+        IOT_FUNCTION_CLEANUP_END();\r
+    }\r
+#endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+/*-----------------------------------------------------------*/\r
+\r
+static void _networkTask( void * pvParameters )\r
+{\r
+    _networkConnection_t * pConnection = NULL;\r
+    BaseType_t socketEvents = 0, i = 0, socketStatus = 0;\r
+    SocketSet_t socketSet = pvParameters;\r
+\r
+    while( true )\r
+    {\r
+        socketEvents = FreeRTOS_select( socketSet, IOT_NETWORK_SOCKET_TIMEOUT_MS );\r
+\r
+        if( socketEvents > 0 )\r
+        {\r
+            for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )\r
+            {\r
+                pConnection = _connections[ i ];\r
+\r
+                if( pConnection != NULL )\r
+                {\r
+                    socketStatus = FreeRTOS_FD_ISSET( pConnection->socket, socketSet );\r
+\r
+                    if( socketStatus & eSELECT_READ )\r
+                    {\r
+                        /* A receive callback must be set; otherwise, select should not\r
+                         * have returned this socket. */\r
+                        configASSERT( pConnection->receiveCallback != NULL );\r
+\r
+                        pConnection->receiveCallback( pConnection,\r
+                                                      pConnection->pReceiveContext );\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        /* This task will receive a notification when cleanup is called. Exit when\r
+         * cleanup is called. */\r
+        if( ulTaskNotifyTake( pdTRUE, 0 ) != 0 )\r
+        {\r
+            break;\r
+        }\r
+    }\r
+\r
+    FreeRTOS_DeleteSocketSet( socketSet );\r
+    vTaskDelete( NULL );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+IotNetworkError_t IotNetworkFreeRTOS_Init( void )\r
+{\r
+    IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        int mbedtlsError = 0;\r
+\r
+        /* Set the mutex functions for mbed TLS thread safety. */\r
+        mbedtls_threading_set_alt( mbedtls_platform_mutex_init,\r
+                                   mbedtls_platform_mutex_free,\r
+                                   mbedtls_platform_mutex_lock,\r
+                                   mbedtls_platform_mutex_unlock );\r
+\r
+        /* Initialize contexts for random number generation. */\r
+        mbedtls_entropy_init( &_entropyContext );\r
+        mbedtls_ctr_drbg_init( &_ctrDrgbContext );\r
+\r
+        /* Add a strong entropy source. At least one is required. */\r
+        mbedtlsError = mbedtls_entropy_add_source( &_entropyContext,\r
+                                                   mbedtls_platform_entropy_poll,\r
+                                                   NULL,\r
+                                                   32,\r
+                                                   MBEDTLS_ENTROPY_SOURCE_STRONG );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to add entropy source, error %d.", mbedtlsError );\r
+\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );\r
+        }\r
+\r
+        /* Seed the random number generator. */\r
+        mbedtlsError = mbedtls_ctr_drbg_seed( &_ctrDrgbContext,\r
+                                              mbedtls_entropy_func,\r
+                                              &_entropyContext,\r
+                                              NULL,\r
+                                              0 );\r
+\r
+        if( mbedtlsError != 0 )\r
+        {\r
+            IotLogError( "Failed to seed PRNG, error %d.", mbedtlsError );\r
+\r
+            IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );\r
+        }\r
+    #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+\r
+    /* Create socket set for network task. */\r
+    _socketSet = FreeRTOS_CreateSocketSet();\r
+\r
+    if( _socketSet == NULL )\r
+    {\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );\r
+    }\r
+\r
+    static StaticTask_t networkTask;\r
+    static StackType_t networkTaskStack[ IOT_NETWORK_TASK_STACK_SIZE ];\r
+\r
+    /* Create the network task. Since valid parameters are provided, this should\r
+     * never fail. */\r
+    _networkTaskHandle = xTaskCreateStatic( _networkTask,\r
+                                            "Network",\r
+                                            IOT_NETWORK_TASK_STACK_SIZE,\r
+                                            _socketSet,\r
+                                            IOT_NETWORK_TASK_PRIORITY,\r
+                                            ( StackType_t * const ) &networkTaskStack,\r
+                                            &networkTask );\r
+    configASSERT( _networkTaskHandle != NULL );\r
+\r
+    IotLogInfo( "Network successfully initialized." );\r
+\r
+    IOT_FUNCTION_EXIT_NO_CLEANUP();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void IotNetworkFreeRTOS_Cleanup( void )\r
+{\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        /* Free the contexts for random number generation. */\r
+        mbedtls_ctr_drbg_free( &_ctrDrgbContext );\r
+        mbedtls_entropy_free( &_entropyContext );\r
+\r
+        /* Clear the mutex functions for mbed TLS thread safety. */\r
+        mbedtls_threading_free_alt();\r
+    #endif\r
+\r
+    xTaskNotifyGive( _networkTaskHandle );\r
+\r
+    IotLogInfo( "Network cleanup done." );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+IotNetworkError_t IotNetworkFreeRTOS_Create( IotNetworkServerInfo_t pServerInfo,\r
+                                             IotNetworkCredentials_t pCredentialInfo,\r
+                                             IotNetworkConnection_t * pConnection )\r
+{\r
+    IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );\r
+    Socket_t tcpSocket = FREERTOS_INVALID_SOCKET;\r
+    BaseType_t socketStatus = 0;\r
+    struct freertos_sockaddr serverAddress = { 0 };\r
+    const TickType_t receiveTimeout = pdMS_TO_TICKS( IOT_NETWORK_SOCKET_TIMEOUT_MS );\r
+    _networkConnection_t * pNewNetworkConnection = NULL;\r
+\r
+    /* Credentials are not used if TLS is disabled. */\r
+    ( void ) pCredentialInfo;\r
+\r
+    /* Check host name length against the maximum length allowed. */\r
+    const size_t hostnameLength = strlen( pServerInfo->pHostName );\r
+\r
+    if( hostnameLength > ( size_t ) MAX_DNS_NAME_LENGTH )\r
+    {\r
+        IotLogError( "Host name length exceeds %d, which is the maximum allowed.",\r
+                     MAX_DNS_NAME_LENGTH );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_BAD_PARAMETER );\r
+    }\r
+\r
+    pNewNetworkConnection = pvPortMalloc( sizeof( _networkConnection_t ) );\r
+\r
+    if( pNewNetworkConnection == NULL )\r
+    {\r
+        IotLogError( "Failed to allocate memory for new network connection." );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );\r
+    }\r
+\r
+    /* Clear the connection information. */\r
+    ( void ) memset( pNewNetworkConnection, 0x00, sizeof( _networkConnection_t ) );\r
+\r
+    /* Create a new TCP socket. */\r
+    tcpSocket = FreeRTOS_socket( FREERTOS_AF_INET,\r
+                                 FREERTOS_SOCK_STREAM,\r
+                                 FREERTOS_IPPROTO_TCP );\r
+\r
+    if( tcpSocket == FREERTOS_INVALID_SOCKET )\r
+    {\r
+        IotLogError( "Failed to create new socket." );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+    }\r
+\r
+    /* Set the timeout for receive. */\r
+    socketStatus = FreeRTOS_setsockopt( tcpSocket,\r
+                                        0,\r
+                                        FREERTOS_SO_RCVTIMEO,\r
+                                        &receiveTimeout,\r
+                                        sizeof( TickType_t ) );\r
+\r
+    if( socketStatus != 0 )\r
+    {\r
+        IotLogError( "Failed to set socket receive timeout." );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+    }\r
+\r
+    /* Establish connection. */\r
+    serverAddress.sin_family = FREERTOS_AF_INET;\r
+    serverAddress.sin_port = FreeRTOS_htons( pServerInfo->port );\r
+    serverAddress.sin_addr = FreeRTOS_gethostbyname( pServerInfo->pHostName );\r
+    serverAddress.sin_len = ( uint8_t ) sizeof( serverAddress );\r
+\r
+    /* Check for errors from DNS lookup. */\r
+    if( serverAddress.sin_addr == 0 )\r
+    {\r
+        IotLogError( "Failed to resolve %s.", pServerInfo->pHostName );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+    }\r
+\r
+    socketStatus = FreeRTOS_connect( tcpSocket,\r
+                                     &serverAddress,\r
+                                     sizeof( serverAddress ) );\r
+\r
+    if( socketStatus != 0 )\r
+    {\r
+        IotLogError( "Failed to establish new connection. Socket status %d.", socketStatus );\r
+        IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );\r
+    }\r
+\r
+    /* Set the socket. */\r
+    pNewNetworkConnection->socket = tcpSocket;\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        /* Set up TLS if credentials are provided. */\r
+        if( pCredentialInfo != NULL )\r
+        {\r
+            status = _tlsSetup( pNewNetworkConnection,\r
+                                pServerInfo->pHostName,\r
+                                pCredentialInfo );\r
+        }\r
+    #endif\r
+\r
+    IOT_FUNCTION_CLEANUP_BEGIN();\r
+\r
+    /* Clean up on failure. */\r
+    if( status != IOT_NETWORK_SUCCESS )\r
+    {\r
+        if( tcpSocket != FREERTOS_INVALID_SOCKET )\r
+        {\r
+            FreeRTOS_closesocket( tcpSocket );\r
+        }\r
+\r
+        /* Clear the connection information. */\r
+        if( pNewNetworkConnection != NULL )\r
+        {\r
+            vPortFree( pNewNetworkConnection );\r
+        }\r
+    }\r
+    else\r
+    {\r
+        /* Create the socket mutex. */\r
+        pNewNetworkConnection->socketMutex = xSemaphoreCreateMutexStatic( &( pNewNetworkConnection->socketMutexStorage ) );\r
+\r
+        /* Set the output parameter. */\r
+        *pConnection = pNewNetworkConnection;\r
+\r
+        IotLogInfo( "(Network connection %p) Connection to %s established.",\r
+                    pNewNetworkConnection,\r
+                    pServerInfo->pHostName );\r
+    }\r
+\r
+    IOT_FUNCTION_CLEANUP_END();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+IotNetworkError_t IotNetworkFreeRTOS_SetReceiveCallback( IotNetworkConnection_t pConnection,\r
+                                                         IotNetworkReceiveCallback_t receiveCallback,\r
+                                                         void * pContext )\r
+{\r
+    IotNetworkError_t status = IOT_NETWORK_SUCCESS;\r
+    BaseType_t i = 0;\r
+\r
+    /* Set the receive callback and context. */\r
+    pConnection->receiveCallback = receiveCallback;\r
+    pConnection->pReceiveContext = pContext;\r
+\r
+    /* Add this connection to the list of connections that select should check. */\r
+    for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )\r
+    {\r
+        if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ],\r
+                                               pConnection,\r
+                                               NULL ) == 1 )\r
+        {\r
+            break;\r
+        }\r
+    }\r
+\r
+    if( i == IOT_NETWORK_MAX_RECEIVE_CALLBACKS )\r
+    {\r
+        status = IOT_NETWORK_NO_MEMORY;\r
+    }\r
+    else\r
+    {\r
+        /* Add this socket to the socket set for the network task. */\r
+        FreeRTOS_FD_SET( pConnection->socket,\r
+                         _socketSet,\r
+                         eSELECT_READ );\r
+    }\r
+\r
+    return status;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+size_t IotNetworkFreeRTOS_Send( IotNetworkConnection_t pConnection,\r
+                                const uint8_t * pMessage,\r
+                                size_t messageLength )\r
+{\r
+    size_t bytesSent = 0;\r
+    BaseType_t socketStatus = 0;\r
+\r
+    /* Only one thread at a time may send on the connection. Lock the send\r
+     * mutex to prevent other threads from sending. */\r
+    if( xSemaphoreTake( pConnection->socketMutex,\r
+                        IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )\r
+    {\r
+        #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+            if( pConnection->secured == pdTRUE )\r
+            {\r
+                while( bytesSent < messageLength )\r
+                {\r
+                    socketStatus = ( BaseType_t ) mbedtls_ssl_write( &( pConnection->ssl.context ),\r
+                                                                     pMessage + bytesSent,\r
+                                                                     messageLength - bytesSent );\r
+\r
+                    if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) ||\r
+                        ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) )\r
+                    {\r
+                        /* Try again for WANT_WRITE and WANT_READ errors. */\r
+                        continue;\r
+                    }\r
+                    else if( socketStatus < 0 )\r
+                    {\r
+                        /* Exit on other errors. */\r
+                        break;\r
+                    }\r
+                    else\r
+                    {\r
+                        bytesSent += ( size_t ) socketStatus;\r
+                        configASSERT( bytesSent <= messageLength );\r
+                    }\r
+                }\r
+            }\r
+            else\r
+        #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+        {\r
+            socketStatus = FreeRTOS_send( pConnection->socket,\r
+                                          pMessage,\r
+                                          messageLength,\r
+                                          0 );\r
+        }\r
+\r
+        if( socketStatus > 0 )\r
+        {\r
+            bytesSent = ( size_t ) socketStatus;\r
+        }\r
+\r
+        xSemaphoreGive( pConnection->socketMutex );\r
+    }\r
+\r
+    IotLogDebug( "(Network connection %p) Sent %lu bytes.",\r
+                 pConnection,\r
+                 ( unsigned long ) bytesSent );\r
+\r
+    return bytesSent;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+size_t IotNetworkFreeRTOS_Receive( IotNetworkConnection_t pConnection,\r
+                                   uint8_t * pBuffer,\r
+                                   size_t bytesRequested )\r
+{\r
+    BaseType_t socketStatus = 0;\r
+    size_t bytesReceived = 0, bytesRemaining = bytesRequested;\r
+\r
+    /* Block and wait for incoming data. */\r
+    while( bytesRemaining > 0 )\r
+    {\r
+        #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+            if( pConnection->secured == pdTRUE )\r
+            {\r
+                if( xSemaphoreTake( pConnection->socketMutex,\r
+                                    IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )\r
+                {\r
+                    socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ),\r
+                                                                    pBuffer + bytesReceived,\r
+                                                                    bytesRequested - bytesReceived );\r
+\r
+                    xSemaphoreGive( pConnection->socketMutex );\r
+\r
+                    if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) ||\r
+                        ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) )\r
+                    {\r
+                        /* Try again for WANT_WRITE and WANT_READ errors. */\r
+                        continue;\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    /* Could not obtain socket mutex, exit. */\r
+                    break;\r
+                }\r
+            }\r
+            else\r
+        #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+        {\r
+            socketStatus = FreeRTOS_recv( pConnection->socket,\r
+                                          pBuffer + bytesReceived,\r
+                                          bytesRemaining,\r
+                                          0 );\r
+\r
+            if( socketStatus == FREERTOS_EWOULDBLOCK )\r
+            {\r
+                /* The return value EWOULDBLOCK means no data was received within\r
+                 * the socket timeout. Ignore it and try again. */\r
+                continue;\r
+            }\r
+        }\r
+\r
+        if( socketStatus < 0 )\r
+        {\r
+            IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus );\r
+            break;\r
+        }\r
+        else\r
+        {\r
+            bytesReceived += ( size_t ) socketStatus;\r
+            bytesRemaining -= ( size_t ) socketStatus;\r
+\r
+            configASSERT( bytesReceived + bytesRemaining == bytesRequested );\r
+        }\r
+    }\r
+\r
+    if( bytesReceived < bytesRequested )\r
+    {\r
+        IotLogWarn( "(Network connection %p) Receive requested %lu bytes, but %lu bytes received instead.",\r
+                    pConnection,\r
+                    ( unsigned long ) bytesRequested,\r
+                    ( unsigned long ) bytesReceived );\r
+    }\r
+    else\r
+    {\r
+        IotLogDebug( "(Network connection %p) Successfully received %lu bytes.",\r
+                     pConnection,\r
+                     ( unsigned long ) bytesRequested );\r
+    }\r
+\r
+    return bytesReceived;\r
+}\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+size_t IotNetworkFreeRTOS_ReceiveUpto( IotNetworkConnection_t pConnection,\r
+                                       uint8_t * pBuffer,\r
+                                       size_t bufferSize )\r
+{\r
+    int32_t socketStatus = 0;\r
+    size_t bytesReceived = 0;\r
+\r
+    /* Caller should never pass a zero-length buffer. */\r
+    configASSERT( bufferSize > 0 );\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        if( pConnection->secured == pdTRUE )\r
+        {\r
+            if( xSemaphoreTake( pConnection->socketMutex,\r
+                                IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )\r
+            {\r
+                do\r
+                {\r
+                    socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ),\r
+                                                                    pBuffer + bytesReceived,\r
+                                                                    bufferSize - bytesReceived );\r
+                } while( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) ||\r
+                         ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) );\r
+\r
+                xSemaphoreGive( pConnection->socketMutex );\r
+            }\r
+            else\r
+            {\r
+                IotLogError( "Could not obtain the socket mutex." );\r
+            }\r
+        }\r
+        else\r
+    #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+    {\r
+        socketStatus = FreeRTOS_recv( pConnection->socket,\r
+                                      pBuffer + bytesReceived,\r
+                                      bufferSize - bytesReceived,\r
+                                      0 );\r
+    }\r
+\r
+    if( socketStatus <= 0 )\r
+    {\r
+        IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus );\r
+    }\r
+    else\r
+    {\r
+        bytesReceived += ( size_t ) socketStatus;\r
+    }\r
+\r
+    IotLogDebug( "Received %lu bytes.",\r
+                 ( unsigned long ) bytesReceived );\r
+\r
+    return bytesReceived;\r
+}\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+IotNetworkError_t IotNetworkFreeRTOS_Close( IotNetworkConnection_t pConnection )\r
+{\r
+    BaseType_t socketStatus = 0, i = 0;\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        /* Notify the peer that the TLS connection is being closed. */\r
+        if( pConnection->secured == pdTRUE )\r
+        {\r
+            if( xSemaphoreTake( pConnection->socketMutex,\r
+                                IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )\r
+            {\r
+                socketStatus = ( BaseType_t ) mbedtls_ssl_close_notify( &( pConnection->ssl.context ) );\r
+\r
+                /* Ignore the WANT_READ and WANT_WRITE return values. */\r
+                if( ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) &&\r
+                    ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) )\r
+                {\r
+                    if( socketStatus == 0 )\r
+                    {\r
+                        IotLogInfo( "(Network connection %p) TLS close-notify sent.",\r
+                                    pConnection );\r
+                    }\r
+                    else\r
+                    {\r
+                        IotLogWarn( "(Network connection %p) Failed to send TLS close-notify, error %d.",\r
+                                    pConnection,\r
+                                    socketStatus );\r
+                    }\r
+                }\r
+\r
+                xSemaphoreGive( pConnection->socketMutex );\r
+            }\r
+        }\r
+    #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */\r
+\r
+    /* Call socket shutdown function to close connection. */\r
+    socketStatus = FreeRTOS_shutdown( pConnection->socket,\r
+                                      FREERTOS_SHUT_RDWR );\r
+\r
+    if( socketStatus != 0 )\r
+    {\r
+        IotLogWarn( "(Network connection %p) Failed to close connection.",\r
+                    pConnection );\r
+    }\r
+    else\r
+    {\r
+        IotLogInfo( "(Network connection %p) Connection closed.",\r
+                    pConnection );\r
+    }\r
+\r
+    /* Remove this connection from Select's socket set (if present). */\r
+    for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )\r
+    {\r
+        if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ], NULL, pConnection ) == 1 )\r
+        {\r
+            FreeRTOS_FD_CLR( pConnection->socket, _socketSet, eSELECT_ALL );\r
+        }\r
+    }\r
+\r
+    return IOT_NETWORK_SUCCESS;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+IotNetworkError_t IotNetworkFreeRTOS_Destroy( IotNetworkConnection_t pConnection )\r
+{\r
+    FreeRTOS_closesocket( pConnection->socket );\r
+\r
+    #if ( IOT_NETWORK_ENABLE_TLS == 1 )\r
+        /* Free mbed TLS contexts. */\r
+        if( pConnection->secured == pdTRUE )\r
+        {\r
+            _sslContextFree( pConnection );\r
+        }\r
+    #endif\r
+\r
+    /* Free memory used by network connection. */\r
+    vPortFree( pConnection );\r
+\r
+    IotLogInfo( "(Network connection %p) Connection destroyed.",\r
+                pConnection );\r
+\r
+    return IOT_NETWORK_SUCCESS;\r
+}\r
+/*-----------------------------------------------------------*/\r