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