Map errors from FreeRTOS+TCP to mbedTLS and make read non-blocking when requesting start of frame (#452)

From the FreeRTOS documentation, pdFREERTOS_ERRNO_ENOSPC means that timeout occurred before any data could be sent or received.
- In the plaintext transport-interface implementation, we would directly return `-pdFREERTOS_ERRNO_ENOSPC`. However, an error like this can occur when the TCP buffer is full, so this ought to be retriable. Libraries that consume the transport interface interpret a return value of 0 to mean that send/recv can be invoked again to get the data. As such, we should appropriately set the return value as 0 when the status is `-pdFREERTOS_ERRNO_ENOSPC`.
- In the mbedTLS port, we would directly return whatever `FreeRTOS_send` or `FreeRTOS_recv` returns. However, sometimes, the return value can be an error. In such cases, we ought to map an error from FreeRTOS+TCP to an equivalent error in mbedTLS. In the case of `-pdFREERTOS_ERRNO_ENOSPC`, we map that to `MBEDTLS_ERR_SSL_TIMEOUT`. When the mbedTLS transport-interface send/recv wrapper sees that value, it appropriately returns 0, so that the library can retry the send/recv. I've verified that when the mbedTLS port returns an error, that same error is returned by `mbedtls_ssl_write` & `mbedtls_ssl_read`.
- The TCP socket may have a receive block time.  If bytesToRecv is greater than 1 then a frame is likely already part way through reception and blocking to wait for the desired number of bytes to be available is the
most efficient thing to do.  If bytesToRecv is 1 then this may be a speculative call to read to find the start of a new frame, in which case blocking is not desirable as it could block an entire protocol agent task for the duration of the read block time and therefore negatively impact performance.  So if bytesToRecv is 1 then don't call recv unless it is known that bytes are already available.

Co-authored-by: abhidixi11 <44424462+abhidixi11@users.noreply.github.com>
Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
This commit is contained in:
Oscar Michael Abrina 2020-12-11 12:51:45 -08:00 committed by GitHub
parent ebd1cdf702
commit f23752164b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 23 deletions

View file

@ -128,15 +128,33 @@ int32_t Plaintext_FreeRTOS_recv( NetworkContext_t * pNetworkContext,
size_t bytesToRecv )
{
PlaintextTransportParams_t * pPlaintextTransportParams = NULL;
int32_t socketStatus = 0;
int32_t socketStatus = 1;
configASSERT( ( pNetworkContext != NULL ) && ( pNetworkContext->pParams != NULL ) );
pPlaintextTransportParams = pNetworkContext->pParams;
socketStatus = FreeRTOS_recv( pPlaintextTransportParams->tcpSocket,
pBuffer,
bytesToRecv,
0 );
/* The TCP socket may have a receive block time. If bytesToRecv is greater
* than 1 then a frame is likely already part way through reception and
* blocking to wait for the desired number of bytes to be available is the
* most efficient thing to do. If bytesToRecv is 1 then this may be a
* speculative call to read to find the start of a new frame, in which case
* blocking is not desirable as it could block an entire protocol agent
* task for the duration of the read block time and therefore negatively
* impact performance. So if bytesToRecv is 1 then don't call recv unless
* it is known that bytes are already available. */
if( bytesToRecv == 1 )
{
socketStatus = ( int32_t ) FreeRTOS_recvcount( pPlaintextTransportParams->tcpSocket );
}
if( socketStatus > 0 )
{
socketStatus = FreeRTOS_recv( pPlaintextTransportParams->tcpSocket,
pBuffer,
bytesToRecv,
0 );
}
return socketStatus;
}
@ -156,5 +174,13 @@ int32_t Plaintext_FreeRTOS_send( NetworkContext_t * pNetworkContext,
bytesToSend,
0 );
if( socketStatus == -pdFREERTOS_ERRNO_ENOSPC )
{
/* The TCP buffers could not accept any more bytes so zero bytes were sent.
* This is not necessarily an error that should cause a disconnect
* unless it persists. */
socketStatus = 0;
}
return socketStatus;
}

View file

@ -118,6 +118,10 @@ PlaintextTransportStatus_t Plaintext_FreeRTOS_Disconnect( const NetworkContext_t
/**
* @brief Receives data from an established TCP connection.
*
* @note When the number of bytes requested is 1, the TCP sockets Rx stream
* is checked for available bytes to read. If there are none, this function
* immediately returns 0 without blocking.
*
* @param[in] pNetworkContext The network context containing the TCP socket
* handle.