in FreeRTOS_Sockets.c [3258:3453]
BaseType_t FreeRTOS_recv( Socket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
BaseType_t xFlags )
{
BaseType_t xByteCount;
FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
TickType_t xRemainingTime;
BaseType_t xTimed = pdFALSE;
TimeOut_t xTimeOut;
EventBits_t xEventBits = ( EventBits_t ) 0;
/* Check if the socket is valid, has type TCP and if it is bound to a
* port. */
if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
{
xByteCount = -pdFREERTOS_ERRNO_EINVAL;
}
else if( ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) != 0U ) &&
( pvBuffer == NULL ) )
{
/* In zero-copy mode, pvBuffer is a pointer to a pointer ( not NULL ). */
xByteCount = -pdFREERTOS_ERRNO_EINVAL;
}
else
{
if( pxSocket->u.xTCP.rxStream != NULL )
{
xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
}
else
{
xByteCount = 0;
}
while( xByteCount == 0 )
{
eIPTCPState_t eState = pxSocket->u.xTCP.ucTCPState;
switch( eState )
{
case eCLOSED:
case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */
case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
{
/* The no-memory error has priority above the non-connected error.
* Both are fatal and will lead to closing the socket. */
xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
}
else
{
xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
}
break;
case eTCP_LISTEN:
case eCONNECT_SYN:
case eSYN_FIRST:
case eSYN_RECEIVED:
case eESTABLISHED:
case eFIN_WAIT_1:
case eFIN_WAIT_2:
case eLAST_ACK:
case eTIME_WAIT:
default:
/* Nothing. */
break;
}
if( xByteCount < 0 )
{
break;
}
if( xTimed == pdFALSE )
{
/* Only in the first round, check for non-blocking. */
xRemainingTime = pxSocket->xReceiveBlockTime;
if( xRemainingTime == ( TickType_t ) 0 )
{
#if ( ipconfigSUPPORT_SIGNALS != 0 )
{
/* Just check for the interrupt flag. */
xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
}
#endif /* ipconfigSUPPORT_SIGNALS */
break;
}
if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
{
break;
}
/* Don't get here a second time. */
xTimed = pdTRUE;
/* Fetch the current time. */
vTaskSetTimeOutState( &xTimeOut );
}
/* Has the timeout been reached? */
if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
{
break;
}
/* Block until there is a down-stream event. */
xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED | ( EventBits_t ) eSOCKET_INTR,
pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
#if ( ipconfigSUPPORT_SIGNALS != 0 )
{
if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
{
break;
}
}
#else
{
( void ) xEventBits;
}
#endif /* ipconfigSUPPORT_SIGNALS */
if( pxSocket->u.xTCP.rxStream != NULL )
{
xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
}
else
{
xByteCount = 0;
}
}
#if ( ipconfigSUPPORT_SIGNALS != 0 )
if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
{
if( ( xEventBits & ( ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED ) ) != 0U )
{
/* Shouldn't have cleared other flags. */
xEventBits &= ~( ( EventBits_t ) eSOCKET_INTR );
( void ) xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
}
xByteCount = -pdFREERTOS_ERRNO_EINTR;
}
else
#endif /* ipconfigSUPPORT_SIGNALS */
if( xByteCount > 0 )
{
if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) == 0U )
{
BaseType_t xIsPeek = ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_PEEK ) != 0U ) ? 1L : 0L;
xByteCount = ( BaseType_t )
uxStreamBufferGet( pxSocket->u.xTCP.rxStream,
0U,
ipPOINTER_CAST( uint8_t *, pvBuffer ),
( size_t ) uxBufferLength,
xIsPeek );
if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
{
/* We had reached the low-water mark, now see if the flag
* can be cleared */
size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
{
pxSocket->u.xTCP.bits.bLowWater = pdFALSE;
pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
pxSocket->u.xTCP.usTimeout = 1U; /* because bLowWater is cleared. */
( void ) xSendEventToIPTask( eTCPTimerEvent );
}
}
}
else
{
/* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, ipPOINTER_CAST( uint8_t * *, pvBuffer ) );
}
}
else
{
/* Nothing. */
}
} /* prvValidSocket() */
return xByteCount;
}