BaseType_t FreeRTOS_recv()

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;
    }