2 * Amazon FreeRTOS Platform V1.1.0
\r
3 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file iot_network_freertos.c
\r
28 * @brief Implementation of the network-related functions from iot_network_freertos.h
\r
29 * for FreeRTOS+TCP sockets.
\r
32 /* The config header is always included first. */
\r
33 #include "iot_config.h"
\r
35 /* Standard includes. */
\r
38 /* FreeRTOS includes. */
\r
39 #include "FreeRTOS.h"
\r
43 /* FreeRTOS+TCP includes. */
\r
44 #include "FreeRTOS_IP.h"
\r
45 #include "FreeRTOS_Sockets.h"
\r
47 /* FreeRTOS-IoT-Libraries includes. */
\r
48 #include "iot_error.h"
\r
49 #include "platform/iot_network_freertos.h"
\r
51 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
52 /* mbed TLS includes. */
\r
53 #include "mbedtls/ctr_drbg.h"
\r
54 #include "mbedtls/entropy.h"
\r
55 #include "mbedtls/ssl.h"
\r
56 #include "mbedtls/threading.h"
\r
57 #include "mbedtls/x509.h"
\r
60 /* Configure logs for the functions in this file. */
\r
61 #ifdef IOT_LOG_LEVEL_NETWORK
\r
62 #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_NETWORK
\r
64 #ifdef IOT_LOG_LEVEL_GLOBAL
\r
65 #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL
\r
67 #define LIBRARY_LOG_LEVEL IOT_LOG_NONE
\r
71 #define LIBRARY_LOG_NAME ( "NET" )
\r
72 #include "iot_logging_setup.h"
\r
74 /* Provide a default value for socket timeout and network task parameters. */
\r
75 #ifndef IOT_NETWORK_SOCKET_TIMEOUT_MS
\r
76 #define IOT_NETWORK_SOCKET_TIMEOUT_MS ( 5000 )
\r
78 #ifndef IOT_NETWORK_TASK_STACK_SIZE
\r
79 #define IOT_NETWORK_TASK_STACK_SIZE ( 2048 )
\r
81 #ifndef IOT_NETWORK_TASK_PRIORITY
\r
82 #define IOT_NETWORK_TASK_PRIORITY ( tskIDLE_PRIORITY )
\r
85 /* Maximum number of simultaneous socket receive callbacks. */
\r
86 #ifndef IOT_NETWORK_MAX_RECEIVE_CALLBACKS
\r
87 #define IOT_NETWORK_MAX_RECEIVE_CALLBACKS ( 2 )
\r
91 * @brief Maximum length of a DNS name.
\r
93 * Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length
\r
96 #define MAX_DNS_NAME_LENGTH ( 253 )
\r
97 /*-----------------------------------------------------------*/
\r
100 * @brief Internal network context.
\r
102 typedef struct _networkConnection
\r
104 Socket_t socket; /**< @brief FreeRTOS+TCP sockets handle. */
\r
105 SemaphoreHandle_t socketMutex; /**< @brief Prevents concurrent threads from using a socket. */
\r
106 StaticSemaphore_t socketMutexStorage; /**< @brief Storage space for socketMutex. */
\r
107 IotNetworkReceiveCallback_t receiveCallback; /**< @brief Network receive callback, if any. */
\r
108 void * pReceiveContext; /**< @brief The context for the receive callback. */
\r
110 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
111 BaseType_t secured; /**< @brief Flag that marks a connection as secured. */
\r
114 * @brief Secured connection context. Valid if `secured` is `pdTRUE`.
\r
118 mbedtls_ssl_config config; /**< @brief SSL connection configuration. */
\r
119 mbedtls_ssl_context context; /**< @brief SSL connection context */
\r
120 mbedtls_x509_crt_profile certProfile; /**< @brief Certificate security profile for this connection. */
\r
121 mbedtls_x509_crt rootCa; /**< @brief Root CA certificate context. */
\r
122 mbedtls_x509_crt clientCert; /**< @brief Client certificate context. */
\r
123 mbedtls_pk_context privKey; /**< @brief Client private key context. */
\r
125 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
126 } _networkConnection_t;
\r
127 /*-----------------------------------------------------------*/
\r
129 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
132 * @brief mbed TLS entropy context for generation of random numbers.
\r
134 static mbedtls_entropy_context _entropyContext;
\r
137 * @brief mbed TLS CTR DRBG context for generation of random numbers.
\r
139 static mbedtls_ctr_drbg_context _ctrDrgbContext;
\r
143 * @brief Handle of the network task.
\r
145 static TaskHandle_t _networkTaskHandle;
\r
148 * @brief Socket set for the network task.
\r
150 static SocketSet_t _socketSet;
\r
153 * @brief Connections in _socketSet.
\r
155 static _networkConnection_t * _connections[ IOT_NETWORK_MAX_RECEIVE_CALLBACKS ];
\r
158 * @brief An #IotNetworkInterface_t that uses the functions in this file.
\r
160 const IotNetworkInterface_t IotNetworkFreeRTOS =
\r
162 .create = IotNetworkFreeRTOS_Create,
\r
163 .setReceiveCallback = IotNetworkFreeRTOS_SetReceiveCallback,
\r
164 .send = IotNetworkFreeRTOS_Send,
\r
165 .receive = IotNetworkFreeRTOS_Receive,
\r
166 .receiveUpto = IotNetworkFreeRTOS_ReceiveUpto,
\r
167 .close = IotNetworkFreeRTOS_Close,
\r
168 .destroy = IotNetworkFreeRTOS_Destroy
\r
170 /*-----------------------------------------------------------*/
\r
172 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
175 * @brief Initialize the mbed TLS structures in a network connection.
\r
177 * @param[in] pNetworkConnection The network connection to initialize.
\r
179 static void _sslContextInit( _networkConnection_t * pNetworkConnection )
\r
181 mbedtls_ssl_config_init( &( pNetworkConnection->ssl.config ) );
\r
182 mbedtls_x509_crt_init( &( pNetworkConnection->ssl.rootCa ) );
\r
183 mbedtls_pk_init( &( pNetworkConnection->ssl.privKey ) );
\r
184 mbedtls_x509_crt_init( &( pNetworkConnection->ssl.clientCert ) );
\r
185 mbedtls_ssl_init( &( pNetworkConnection->ssl.context ) );
\r
187 /*-----------------------------------------------------------*/
\r
190 * @brief Free the mbed TLS structures in a network connection.
\r
192 * @param[in] pNetworkConnection The network connection with the contexts to free.
\r
194 static void _sslContextFree( _networkConnection_t * pNetworkConnection )
\r
196 mbedtls_ssl_free( &( pNetworkConnection->ssl.context ) );
\r
197 mbedtls_x509_crt_free( &( pNetworkConnection->ssl.rootCa ) );
\r
198 mbedtls_x509_crt_free( &( pNetworkConnection->ssl.clientCert ) );
\r
199 mbedtls_pk_free( &( pNetworkConnection->ssl.privKey ) );
\r
200 mbedtls_ssl_config_free( &( pNetworkConnection->ssl.config ) );
\r
202 /*-----------------------------------------------------------*/
\r
205 * @brief Set up TLS on a TCP connection.
\r
207 * @param[in] pNetworkConnection An established TCP connection.
\r
208 * @param[in] pServerName Remote host name, used for server name indication.
\r
209 * @param[in] pCredentials TLS setup parameters.
\r
211 * @return #IOT_NETWORK_SUCCESS, #IOT_NETWORK_FAILURE, #IOT_NETWORK_NO_MEMORY,
\r
212 * or #IOT_NETWORK_SYSTEM_ERROR.
\r
214 static IotNetworkError_t _tlsSetup( _networkConnection_t * pNetworkConnection,
\r
215 const char * pServerName,
\r
216 IotNetworkCredentials_t pCredentials )
\r
218 IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );
\r
219 int mbedtlsError = 0;
\r
221 /* Initialize the mbed TLS context structures. */
\r
222 _sslContextInit( pNetworkConnection );
\r
224 mbedtlsError = mbedtls_ssl_config_defaults( &( pNetworkConnection->ssl.config ),
\r
225 MBEDTLS_SSL_IS_CLIENT,
\r
226 MBEDTLS_SSL_TRANSPORT_STREAM,
\r
227 MBEDTLS_SSL_PRESET_DEFAULT );
\r
229 if( mbedtlsError != 0 )
\r
231 IotLogError( "Failed to set default SSL configuration, error %d.", mbedtlsError );
\r
233 /* Per mbed TLS docs, mbedtls_ssl_config_defaults only fails on memory allocation. */
\r
234 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );
\r
237 /* Set up the certificate security profile, starting from the default value. */
\r
238 pNetworkConnection->ssl.certProfile = mbedtls_x509_crt_profile_default;
\r
240 /* test.mosquitto.org only provides a 1024-bit RSA certificate, which is
\r
241 * not acceptable by the default mbed TLS certificate security profile.
\r
242 * For the purposes of this demo, allow the use of 1024-bit RSA certificates.
\r
243 * This block should be removed otherwise. */
\r
244 if( strncmp( pServerName, "test.mosquitto.org", strlen( pServerName ) ) == 0 )
\r
246 pNetworkConnection->ssl.certProfile.rsa_min_bitlen = 1024;
\r
249 /* Set SSL authmode and the RNG context. */
\r
250 mbedtls_ssl_conf_authmode( &( pNetworkConnection->ssl.config ),
\r
251 MBEDTLS_SSL_VERIFY_REQUIRED );
\r
252 mbedtls_ssl_conf_rng( &( pNetworkConnection->ssl.config ),
\r
253 mbedtls_ctr_drbg_random,
\r
254 &_ctrDrgbContext );
\r
255 mbedtls_ssl_conf_cert_profile( &( pNetworkConnection->ssl.config ),
\r
256 &( pNetworkConnection->ssl.certProfile ) );
\r
258 /* Parse the server root CA certificate into the SSL context. */
\r
259 mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.rootCa ),
\r
260 ( const unsigned char * ) pCredentials->pRootCa,
\r
261 pCredentials->rootCaSize );
\r
263 if( mbedtlsError != 0 )
\r
265 IotLogError( "Failed to parse server root CA certificate, error %d.",
\r
268 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
271 mbedtls_ssl_conf_ca_chain( &( pNetworkConnection->ssl.config ),
\r
272 &( pNetworkConnection->ssl.rootCa ),
\r
275 if( ( pCredentials->pPrivateKey != NULL ) && ( pCredentials->pClientCert != NULL ) )
\r
277 /* Setup the client private key. */
\r
278 mbedtlsError = mbedtls_pk_parse_key( &( pNetworkConnection->ssl.privKey ),
\r
279 ( const unsigned char * ) pCredentials->pPrivateKey,
\r
280 pCredentials->privateKeySize,
\r
284 if( mbedtlsError != 0 )
\r
286 IotLogError( "Failed to parse client certificate, error %d.",
\r
289 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
292 /* Setup the client certificate. */
\r
293 mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.clientCert ),
\r
294 ( const unsigned char * ) pCredentials->pClientCert,
\r
295 pCredentials->clientCertSize );
\r
297 if( mbedtlsError != 0 )
\r
299 IotLogError( "Failed to parse the client private key, error %d.",
\r
302 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
305 mbedtls_ssl_conf_own_cert( &( pNetworkConnection->ssl.config ),
\r
306 &( pNetworkConnection->ssl.clientCert ),
\r
307 &( pNetworkConnection->ssl.privKey ) );
\r
310 /* Initialize the mbed TLS secured connection context. */
\r
311 mbedtlsError = mbedtls_ssl_setup( &( pNetworkConnection->ssl.context ),
\r
312 &( pNetworkConnection->ssl.config ) );
\r
314 if( mbedtlsError != 0 )
\r
316 IotLogError( "Failed to set up mbed TLS SSL context, error %d.",
\r
319 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
322 /* Set the underlying IO for the TLS connection. */
\r
323 mbedtls_ssl_set_bio( &( pNetworkConnection->ssl.context ),
\r
324 pNetworkConnection->socket,
\r
325 mbedtls_platform_send,
\r
326 mbedtls_platform_recv,
\r
329 /* Enable SNI if requested. */
\r
330 if( pCredentials->disableSni == false )
\r
332 mbedtlsError = mbedtls_ssl_set_hostname( &( pNetworkConnection->ssl.context ),
\r
335 if( mbedtlsError != 0 )
\r
337 IotLogError( "Failed to set server name, error %d.", mbedtlsError );
\r
339 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
343 /* Perform the TLS handshake. */
\r
346 mbedtlsError = mbedtls_ssl_handshake( &( pNetworkConnection->ssl.context ) );
\r
347 } while( ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_READ ) ||
\r
348 ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_WRITE ) );
\r
350 if( mbedtlsError != 0 )
\r
352 IotLogError( "Failed to perform TLS handshake, error %d.", mbedtlsError );
\r
354 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );
\r
357 /* Clean up on error. */
\r
358 IOT_FUNCTION_CLEANUP_BEGIN();
\r
360 if( status != IOT_NETWORK_SUCCESS )
\r
362 _sslContextFree( pNetworkConnection );
\r
366 pNetworkConnection->secured = pdTRUE;
\r
368 IotLogInfo( "(Network connection %p) TLS handshake successful.",
\r
369 pNetworkConnection );
\r
372 IOT_FUNCTION_CLEANUP_END();
\r
374 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
375 /*-----------------------------------------------------------*/
\r
377 static void _networkTask( void * pvParameters )
\r
379 _networkConnection_t * pConnection = NULL;
\r
380 BaseType_t socketEvents = 0, i = 0, socketStatus = 0;
\r
381 SocketSet_t socketSet = pvParameters;
\r
385 socketEvents = FreeRTOS_select( socketSet, IOT_NETWORK_SOCKET_TIMEOUT_MS );
\r
387 if( socketEvents > 0 )
\r
389 for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )
\r
391 pConnection = _connections[ i ];
\r
393 if( pConnection != NULL )
\r
395 socketStatus = FreeRTOS_FD_ISSET( pConnection->socket, socketSet );
\r
397 if( socketStatus & eSELECT_READ )
\r
399 /* A receive callback must be set; otherwise, select should not
\r
400 * have returned this socket. */
\r
401 configASSERT( pConnection->receiveCallback != NULL );
\r
403 pConnection->receiveCallback( pConnection,
\r
404 pConnection->pReceiveContext );
\r
410 /* This task will receive a notification when cleanup is called. Exit when
\r
411 * cleanup is called. */
\r
412 if( ulTaskNotifyTake( pdTRUE, 0 ) != 0 )
\r
418 FreeRTOS_DeleteSocketSet( socketSet );
\r
419 vTaskDelete( NULL );
\r
421 /*-----------------------------------------------------------*/
\r
423 IotNetworkError_t IotNetworkFreeRTOS_Init( void )
\r
425 IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );
\r
427 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
428 int mbedtlsError = 0;
\r
430 /* Set the mutex functions for mbed TLS thread safety. */
\r
431 mbedtls_threading_set_alt( mbedtls_platform_mutex_init,
\r
432 mbedtls_platform_mutex_free,
\r
433 mbedtls_platform_mutex_lock,
\r
434 mbedtls_platform_mutex_unlock );
\r
436 /* Initialize contexts for random number generation. */
\r
437 mbedtls_entropy_init( &_entropyContext );
\r
438 mbedtls_ctr_drbg_init( &_ctrDrgbContext );
\r
440 /* Add a strong entropy source. At least one is required. */
\r
441 mbedtlsError = mbedtls_entropy_add_source( &_entropyContext,
\r
442 mbedtls_platform_entropy_poll,
\r
445 MBEDTLS_ENTROPY_SOURCE_STRONG );
\r
447 if( mbedtlsError != 0 )
\r
449 IotLogError( "Failed to add entropy source, error %d.", mbedtlsError );
\r
451 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );
\r
454 /* Seed the random number generator. */
\r
455 mbedtlsError = mbedtls_ctr_drbg_seed( &_ctrDrgbContext,
\r
456 mbedtls_entropy_func,
\r
461 if( mbedtlsError != 0 )
\r
463 IotLogError( "Failed to seed PRNG, error %d.", mbedtlsError );
\r
465 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );
\r
467 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
469 /* Create socket set for network task. */
\r
470 _socketSet = FreeRTOS_CreateSocketSet();
\r
472 if( _socketSet == NULL )
\r
474 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE );
\r
477 static StaticTask_t networkTask;
\r
478 static StackType_t networkTaskStack[ IOT_NETWORK_TASK_STACK_SIZE ];
\r
480 /* Create the network task. Since valid parameters are provided, this should
\r
482 _networkTaskHandle = xTaskCreateStatic( _networkTask,
\r
484 IOT_NETWORK_TASK_STACK_SIZE,
\r
486 IOT_NETWORK_TASK_PRIORITY,
\r
487 ( StackType_t * const ) &networkTaskStack,
\r
489 configASSERT( _networkTaskHandle != NULL );
\r
491 IotLogInfo( "Network successfully initialized." );
\r
493 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
495 /*-----------------------------------------------------------*/
\r
497 void IotNetworkFreeRTOS_Cleanup( void )
\r
499 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
500 /* Free the contexts for random number generation. */
\r
501 mbedtls_ctr_drbg_free( &_ctrDrgbContext );
\r
502 mbedtls_entropy_free( &_entropyContext );
\r
504 /* Clear the mutex functions for mbed TLS thread safety. */
\r
505 mbedtls_threading_free_alt();
\r
508 xTaskNotifyGive( _networkTaskHandle );
\r
510 IotLogInfo( "Network cleanup done." );
\r
512 /*-----------------------------------------------------------*/
\r
514 IotNetworkError_t IotNetworkFreeRTOS_Create( IotNetworkServerInfo_t pServerInfo,
\r
515 IotNetworkCredentials_t pCredentialInfo,
\r
516 IotNetworkConnection_t * pConnection )
\r
518 IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS );
\r
519 Socket_t tcpSocket = FREERTOS_INVALID_SOCKET;
\r
520 BaseType_t socketStatus = 0;
\r
521 struct freertos_sockaddr serverAddress = { 0 };
\r
522 const TickType_t receiveTimeout = pdMS_TO_TICKS( IOT_NETWORK_SOCKET_TIMEOUT_MS );
\r
523 _networkConnection_t * pNewNetworkConnection = NULL;
\r
525 /* Credentials are not used if TLS is disabled. */
\r
526 ( void ) pCredentialInfo;
\r
528 /* Check host name length against the maximum length allowed. */
\r
529 const size_t hostnameLength = strlen( pServerInfo->pHostName );
\r
531 if( hostnameLength > ( size_t ) MAX_DNS_NAME_LENGTH )
\r
533 IotLogError( "Host name length exceeds %d, which is the maximum allowed.",
\r
534 MAX_DNS_NAME_LENGTH );
\r
535 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_BAD_PARAMETER );
\r
538 pNewNetworkConnection = pvPortMalloc( sizeof( _networkConnection_t ) );
\r
540 if( pNewNetworkConnection == NULL )
\r
542 IotLogError( "Failed to allocate memory for new network connection." );
\r
543 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );
\r
546 /* Clear the connection information. */
\r
547 ( void ) memset( pNewNetworkConnection, 0x00, sizeof( _networkConnection_t ) );
\r
549 /* Create a new TCP socket. */
\r
550 tcpSocket = FreeRTOS_socket( FREERTOS_AF_INET,
\r
551 FREERTOS_SOCK_STREAM,
\r
552 FREERTOS_IPPROTO_TCP );
\r
554 if( tcpSocket == FREERTOS_INVALID_SOCKET )
\r
556 IotLogError( "Failed to create new socket." );
\r
557 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
560 /* Set the timeout for receive. */
\r
561 socketStatus = FreeRTOS_setsockopt( tcpSocket,
\r
563 FREERTOS_SO_RCVTIMEO,
\r
565 sizeof( TickType_t ) );
\r
567 if( socketStatus != 0 )
\r
569 IotLogError( "Failed to set socket receive timeout." );
\r
570 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
573 /* Establish connection. */
\r
574 serverAddress.sin_family = FREERTOS_AF_INET;
\r
575 serverAddress.sin_port = FreeRTOS_htons( pServerInfo->port );
\r
576 serverAddress.sin_addr = FreeRTOS_gethostbyname( pServerInfo->pHostName );
\r
577 serverAddress.sin_len = ( uint8_t ) sizeof( serverAddress );
\r
579 /* Check for errors from DNS lookup. */
\r
580 if( serverAddress.sin_addr == 0 )
\r
582 IotLogError( "Failed to resolve %s.", pServerInfo->pHostName );
\r
583 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
586 socketStatus = FreeRTOS_connect( tcpSocket,
\r
588 sizeof( serverAddress ) );
\r
590 if( socketStatus != 0 )
\r
592 IotLogError( "Failed to establish new connection. Socket status %d.", socketStatus );
\r
593 IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR );
\r
596 /* Set the socket. */
\r
597 pNewNetworkConnection->socket = tcpSocket;
\r
599 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
600 /* Set up TLS if credentials are provided. */
\r
601 if( pCredentialInfo != NULL )
\r
603 status = _tlsSetup( pNewNetworkConnection,
\r
604 pServerInfo->pHostName,
\r
609 IOT_FUNCTION_CLEANUP_BEGIN();
\r
611 /* Clean up on failure. */
\r
612 if( status != IOT_NETWORK_SUCCESS )
\r
614 if( tcpSocket != FREERTOS_INVALID_SOCKET )
\r
616 FreeRTOS_closesocket( tcpSocket );
\r
619 /* Clear the connection information. */
\r
620 if( pNewNetworkConnection != NULL )
\r
622 vPortFree( pNewNetworkConnection );
\r
627 /* Create the socket mutex. */
\r
628 pNewNetworkConnection->socketMutex = xSemaphoreCreateMutexStatic( &( pNewNetworkConnection->socketMutexStorage ) );
\r
630 /* Set the output parameter. */
\r
631 *pConnection = pNewNetworkConnection;
\r
633 IotLogInfo( "(Network connection %p) Connection to %s established.",
\r
634 pNewNetworkConnection,
\r
635 pServerInfo->pHostName );
\r
638 IOT_FUNCTION_CLEANUP_END();
\r
640 /*-----------------------------------------------------------*/
\r
642 IotNetworkError_t IotNetworkFreeRTOS_SetReceiveCallback( IotNetworkConnection_t pConnection,
\r
643 IotNetworkReceiveCallback_t receiveCallback,
\r
646 IotNetworkError_t status = IOT_NETWORK_SUCCESS;
\r
649 /* Set the receive callback and context. */
\r
650 pConnection->receiveCallback = receiveCallback;
\r
651 pConnection->pReceiveContext = pContext;
\r
653 /* Add this connection to the list of connections that select should check. */
\r
654 for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )
\r
656 if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ],
\r
664 if( i == IOT_NETWORK_MAX_RECEIVE_CALLBACKS )
\r
666 status = IOT_NETWORK_NO_MEMORY;
\r
670 /* Add this socket to the socket set for the network task. */
\r
671 FreeRTOS_FD_SET( pConnection->socket,
\r
678 /*-----------------------------------------------------------*/
\r
680 size_t IotNetworkFreeRTOS_Send( IotNetworkConnection_t pConnection,
\r
681 const uint8_t * pMessage,
\r
682 size_t messageLength )
\r
684 size_t bytesSent = 0;
\r
685 BaseType_t socketStatus = 0;
\r
687 /* Only one thread at a time may send on the connection. Lock the send
\r
688 * mutex to prevent other threads from sending. */
\r
689 if( xSemaphoreTake( pConnection->socketMutex,
\r
690 IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )
\r
692 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
693 if( pConnection->secured == pdTRUE )
\r
695 while( bytesSent < messageLength )
\r
697 socketStatus = ( BaseType_t ) mbedtls_ssl_write( &( pConnection->ssl.context ),
\r
698 pMessage + bytesSent,
\r
699 messageLength - bytesSent );
\r
701 if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) ||
\r
702 ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) )
\r
704 /* Try again for WANT_WRITE and WANT_READ errors. */
\r
707 else if( socketStatus < 0 )
\r
709 /* Exit on other errors. */
\r
714 bytesSent += ( size_t ) socketStatus;
\r
715 configASSERT( bytesSent <= messageLength );
\r
720 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
722 socketStatus = FreeRTOS_send( pConnection->socket,
\r
728 if( socketStatus > 0 )
\r
730 bytesSent = ( size_t ) socketStatus;
\r
733 xSemaphoreGive( pConnection->socketMutex );
\r
736 IotLogDebug( "(Network connection %p) Sent %lu bytes.",
\r
738 ( unsigned long ) bytesSent );
\r
742 /*-----------------------------------------------------------*/
\r
744 size_t IotNetworkFreeRTOS_Receive( IotNetworkConnection_t pConnection,
\r
746 size_t bytesRequested )
\r
748 BaseType_t socketStatus = 0;
\r
749 size_t bytesReceived = 0, bytesRemaining = bytesRequested;
\r
751 /* Block and wait for incoming data. */
\r
752 while( bytesRemaining > 0 )
\r
754 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
755 if( pConnection->secured == pdTRUE )
\r
757 if( xSemaphoreTake( pConnection->socketMutex,
\r
758 IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )
\r
760 socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ),
\r
761 pBuffer + bytesReceived,
\r
762 bytesRequested - bytesReceived );
\r
764 xSemaphoreGive( pConnection->socketMutex );
\r
766 if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) ||
\r
767 ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) )
\r
769 /* Try again for WANT_WRITE and WANT_READ errors. */
\r
775 /* Could not obtain socket mutex, exit. */
\r
780 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
782 socketStatus = FreeRTOS_recv( pConnection->socket,
\r
783 pBuffer + bytesReceived,
\r
787 if( socketStatus == FREERTOS_EWOULDBLOCK )
\r
789 /* The return value EWOULDBLOCK means no data was received within
\r
790 * the socket timeout. Ignore it and try again. */
\r
795 if( socketStatus < 0 )
\r
797 IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus );
\r
802 bytesReceived += ( size_t ) socketStatus;
\r
803 bytesRemaining -= ( size_t ) socketStatus;
\r
805 configASSERT( bytesReceived + bytesRemaining == bytesRequested );
\r
809 if( bytesReceived < bytesRequested )
\r
811 IotLogWarn( "(Network connection %p) Receive requested %lu bytes, but %lu bytes received instead.",
\r
813 ( unsigned long ) bytesRequested,
\r
814 ( unsigned long ) bytesReceived );
\r
818 IotLogDebug( "(Network connection %p) Successfully received %lu bytes.",
\r
820 ( unsigned long ) bytesRequested );
\r
823 return bytesReceived;
\r
826 /*-----------------------------------------------------------*/
\r
828 size_t IotNetworkFreeRTOS_ReceiveUpto( IotNetworkConnection_t pConnection,
\r
830 size_t bufferSize )
\r
832 int32_t socketStatus = 0;
\r
833 size_t bytesReceived = 0;
\r
835 /* Caller should never pass a zero-length buffer. */
\r
836 configASSERT( bufferSize > 0 );
\r
838 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
839 if( pConnection->secured == pdTRUE )
\r
841 if( xSemaphoreTake( pConnection->socketMutex,
\r
842 IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )
\r
846 socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ),
\r
847 pBuffer + bytesReceived,
\r
848 bufferSize - bytesReceived );
\r
849 } while( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) ||
\r
850 ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) );
\r
852 xSemaphoreGive( pConnection->socketMutex );
\r
856 IotLogError( "Could not obtain the socket mutex." );
\r
860 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
862 socketStatus = FreeRTOS_recv( pConnection->socket,
\r
863 pBuffer + bytesReceived,
\r
864 bufferSize - bytesReceived,
\r
868 if( socketStatus <= 0 )
\r
870 IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus );
\r
874 bytesReceived += ( size_t ) socketStatus;
\r
877 IotLogDebug( "Received %lu bytes.",
\r
878 ( unsigned long ) bytesReceived );
\r
880 return bytesReceived;
\r
883 /*-----------------------------------------------------------*/
\r
885 IotNetworkError_t IotNetworkFreeRTOS_Close( IotNetworkConnection_t pConnection )
\r
887 BaseType_t socketStatus = 0, i = 0;
\r
889 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
890 /* Notify the peer that the TLS connection is being closed. */
\r
891 if( pConnection->secured == pdTRUE )
\r
893 if( xSemaphoreTake( pConnection->socketMutex,
\r
894 IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE )
\r
896 socketStatus = ( BaseType_t ) mbedtls_ssl_close_notify( &( pConnection->ssl.context ) );
\r
898 /* Ignore the WANT_READ and WANT_WRITE return values. */
\r
899 if( ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) &&
\r
900 ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) )
\r
902 if( socketStatus == 0 )
\r
904 IotLogInfo( "(Network connection %p) TLS close-notify sent.",
\r
909 IotLogWarn( "(Network connection %p) Failed to send TLS close-notify, error %d.",
\r
915 xSemaphoreGive( pConnection->socketMutex );
\r
918 #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */
\r
920 /* Call socket shutdown function to close connection. */
\r
921 socketStatus = FreeRTOS_shutdown( pConnection->socket,
\r
922 FREERTOS_SHUT_RDWR );
\r
924 if( socketStatus != 0 )
\r
926 IotLogWarn( "(Network connection %p) Failed to close connection.",
\r
931 IotLogInfo( "(Network connection %p) Connection closed.",
\r
935 /* Remove this connection from Select's socket set (if present). */
\r
936 for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ )
\r
938 if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ], NULL, pConnection ) == 1 )
\r
940 FreeRTOS_FD_CLR( pConnection->socket, _socketSet, eSELECT_ALL );
\r
944 return IOT_NETWORK_SUCCESS;
\r
946 /*-----------------------------------------------------------*/
\r
948 IotNetworkError_t IotNetworkFreeRTOS_Destroy( IotNetworkConnection_t pConnection )
\r
950 FreeRTOS_closesocket( pConnection->socket );
\r
952 #if ( IOT_NETWORK_ENABLE_TLS == 1 )
\r
953 /* Free mbed TLS contexts. */
\r
954 if( pConnection->secured == pdTRUE )
\r
956 _sslContextFree( pConnection );
\r
960 /* Free memory used by network connection. */
\r
961 vPortFree( pConnection );
\r
963 IotLogInfo( "(Network connection %p) Connection destroyed.",
\r
966 return IOT_NETWORK_SUCCESS;
\r
968 /*-----------------------------------------------------------*/
\r