in platform/posix/transport/src/openssl_posix.c [753:862]
int32_t Openssl_Recv( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
OpensslParams_t * pOpensslParams = NULL;
int32_t bytesReceived = 0;
if( !isValidNetworkContext( pNetworkContext ) ||
( pBuffer == NULL ) ||
( bytesToRecv == 0 ) )
{
LogError( ( "Parameter check failed: invalid input, pNetworkContext is invalid or pBuffer = %p, bytesToRecv = %lu", pBuffer, bytesToRecv ) );
bytesReceived = -1;
}
else
{
int32_t pollStatus = 1, readStatus = 1, sslError = 0;
uint8_t shouldRead = 0U;
struct pollfd pollFds;
pOpensslParams = pNetworkContext->pParams;
/* Initialize the file descriptor.
* #POLLPRI corresponds to high-priority data while #POLLIN corresponds
* to any other data that may be read. */
pollFds.events = POLLIN | POLLPRI;
pollFds.revents = 0;
/* Set the file descriptor for poll. */
pollFds.fd = pOpensslParams->socketDescriptor;
/* #SSL_pending returns a value > 0 if application data
* from the last processed TLS record remains to be read.
* This implementation will ALWAYS block when the number of bytes
* requested is greater than 1. Otherwise, poll the socket first
* as blocking may negatively impact performance by waiting for the
* entire duration of the socket timeout even when no data is available. */
if( ( bytesToRecv > 1 ) || ( SSL_pending( pOpensslParams->pSsl ) > 0 ) )
{
shouldRead = 1U;
}
else
{
/* Speculative read for the start of a payload.
* Note: This is done to avoid blocking when no
* data is available to be read from the socket. */
pollStatus = poll( &pollFds, 1, 0 );
}
if( pollStatus < 0 )
{
bytesReceived = -1;
}
else if( pollStatus == 0 )
{
/* No data available to be read from the socket. */
bytesReceived = 0;
}
else
{
shouldRead = 1U;
}
if( shouldRead == 1U )
{
/* Blocking SSL read of data.
* Note: The TLS record may only be partially received or unprocessed,
* so it is possible that no processed application data is returned
* even though the socket has data available to be read. */
readStatus = ( int32_t ) SSL_read( pOpensslParams->pSsl, pBuffer,
( int32_t ) bytesToRecv );
/* Successfully read of application data. */
if( readStatus > 0 )
{
bytesReceived = readStatus;
}
}
/* Handle error return status if transport read did not succeed. */
if( readStatus <= 0 )
{
sslError = SSL_get_error( pOpensslParams->pSsl, readStatus );
if( sslError == SSL_ERROR_WANT_READ )
{
/* The OpenSSL documentation mentions that SSL_Read can provide a
* return code of SSL_ERROR_WANT_READ in blocking mode, if the SSL
* context is not configured with with the SSL_MODE_AUTO_RETRY. This
* error code means that the SSL_read() operation needs to be retried
* to complete the read operation. Thus, setting the return value of
* this function as zero to represent that no data was received from
* the network. */
bytesReceived = 0;
}
else
{
LogError( ( "Failed to receive data over network: SSL_read failed: "
"ErrorStatus=%s.",
ERR_reason_error_string( sslError ) ) );
/* The transport interface requires zero return code only when the
* receive operation can be retried to achieve success. Thus, convert
* a zero error code to a negative return value as this cannot be
* retried. */
bytesReceived = -1;
}
}
}
return bytesReceived;
}