Frame not received in a TCP echo server

Hello !

I am working on a TCP echo server using FreeRTOS+TCP on a STM32F4. I used example code to run my server but the program is stuck in FreeRTOS_recv() function.
I checked several things :

  1. ARP is working, I can see with wireshark that the asking from my computer is well answered with my STM32.

  2. Ping is working well too.

  3. Connection on my server is working. when the client try to connect to my server, the connection is good and my code goes into FreeRTOS_recv.

  4. The frame reception is working. When sending “test” with my client, my code breaks in prvTCPHandleState and the frame is processed.

  5. Something is a bit weird. In FreeRTOS_TCP_IP.c in prvStoreRxData() function, my code does not enter in lTCPAddRxdata which seems to send the data to user part. the reason is that pxTCPWindow->ulUserDataLength is equal to 0.

     	/* Now lTCPAddRxdata() will move the rxHead pointer forward
     	so data becomes available to the user immediately
     	In case the low-water mark is reached, bLowWater will be set. */
     	if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0UL ) )
     	{
     		( void ) lTCPAddRxdata( pxSocket, 0UL, NULL, pxTCPWindow->ulUserDataLength );
     		pxTCPWindow->ulUserDataLength = 0;
     	}
    

Here is my main.cpp :

    int main(void)
    {
        MainInit();


    /* Initialise the RTOS’s TCP/IP stack.  The tasks that use the network
    are created in the vApplicationIPNetworkEventHook() hook function
    below.  The hook function is called when the network connects. */
    FreeRTOS_IPInit( ucIPAddress,
                     ucNetMask,
                     ucGatewayAddress,
                     ucDNSServerAddress,
                     ucMACAddress );


    // NVIC_SetPriorityGrouping( 0 ); // Demandé d'être mis a cette valeur dans port.c
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); // Demandé d'etre mis a 4 dans https://www.freertos.org/RTOS-Cortex-M3-M4.html


	/* Start the scheduler. */
	vTaskStartScheduler();

    // CANT GO HERE !
    ASSERT(0);

    return (0);
    }

    static void TcpServerTask( void *pvParameters )
    {
        printf("TcpServerTask created\n\r");

    struct freertos_sockaddr xClient, xBindAddress;
    Socket_t xListeningSocket, xConnectedSocket;
    socklen_t xSize = sizeof( xClient );
    static const TickType_t xReceiveTimeOut = portMAX_DELAY;
    const BaseType_t xBacklog = 20;
#define BUFFER_SIZE 1500
    static char cRxedData[ BUFFER_SIZE ];
    BaseType_t lBytesReceived;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                                        FREERTOS_SOCK_STREAM,  /* SOCK_STREAM for TCP. */
                                        FREERTOS_IPPROTO_TCP  );

    /* Check the socket was created. */
    ASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

    /* If FREERTOS_SO_RCVBUF or FREERTOS_SO_SNDBUF are to be used with
    FreeRTOS_setsockopt() to change the buffer sizes from their default then do
    it here!.  (see the FreeRTOS_setsockopt() documentation. */

    /* If ipconfigUSE_TCP_WIN is set to 1 and FREERTOS_SO_WIN_PROPERTIES is to
    be used with FreeRTOS_setsockopt() to change the sliding window size from
    its default then do it here! (see the FreeRTOS_setsockopt()
    documentation. */

    /* Set a time out so accept() will just wait for a connection. */
    FreeRTOS_setsockopt( xListeningSocket,
                         0,
                         FREERTOS_SO_RCVTIMEO,
                         &xReceiveTimeOut,
                         sizeof( xReceiveTimeOut ) );

    /* Set the listening port to 1337. */
    xBindAddress.sin_port = ( uint16_t ) 1337;
    xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

    /* Bind the socket to the port that the client RTOS task will send to. */
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    /* Set the socket into a listening state so it can accept connections.
    The maximum number of simultaneous connections is limited to 20. */
    FreeRTOS_listen( xListeningSocket, xBacklog );


    for(;;)
    {
        /* Wait for incoming connections. */
        xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
        ASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );

        /* Receive another block of data into the cRxedData buffer. */
        lBytesReceived = FreeRTOS_recv( xListeningSocket, &cRxedData, BUFFER_SIZE, 0 );

        if( lBytesReceived > 0 )
        {
            BaseType_t xAlreadyTransmitted = 0, xBytesSent = 0;
            size_t xLenToSend;
            /* Data was received, process it here. */

            /* Keep sending until the entire buffer has been sent. */
            while( xAlreadyTransmitted < lBytesReceived )
            {
                /* How many bytes are left to send? */
                xLenToSend = lBytesReceived - xAlreadyTransmitted;
                xBytesSent = FreeRTOS_send( /* The socket being sent to. */
                                            xListeningSocket,
                                            /* The data being sent. */
                                            &( cRxedData[ xAlreadyTransmitted ] ),
                                            /* The remaining length of data to send. */
                                            xLenToSend,
                                            /* ulFlags. */
                                            0 );

                if( xBytesSent >= 0 )
                {
                    /* Data was sent successfully. */
                    xAlreadyTransmitted += xBytesSent;
                }
                else
                {
                    /* Error – break out of the loop for graceful socket close. */
                    break;
                }
            }

        }
        else if( lBytesReceived == 0 )
        {
            /* No data was received, but FreeRTOS_recv() did not return an error.
            Timeout? */
        }
        else
        {
            /* Error (maybe the connected socket already shut down the socket?).
            Attempt graceful shutdown. */
            FreeRTOS_shutdown( xListeningSocket, FREERTOS_SHUT_RDWR );
            break;
        }


    }

    /* The RTOS task will get here if an error is received on a read.  Ensure the
    socket has shut down (indicated by FreeRTOS_recv() returning a FREERTOS_EINVAL
    error before closing the socket). */

    while( FreeRTOS_recv( xListeningSocket, cRxedData, lBytesReceived, 0 ) >= 0 )
    {
        /* Wait for shutdown to complete.  If a receive block time is used then
        this delay will not be necessary as FreeRTOS_recv() will place the RTOS task
        into the Blocked state anyway. */
        vTaskDelay( 250 );

        /* Note – real applications should implement a timeout here, not just
        loop forever. */
    }

    /* Shutdown is complete and the socket can be safely closed. */
    FreeRTOS_closesocket( xListeningSocket );

    /* Must not drop off the end of the RTOS task – delete the RTOS task. */
    vTaskDelete( NULL );
}

So, it seems that FreeRTOS can not send the frame to the user part. but I don’t know why. Have you ever experienced this situation ?

Thank you.
fgu

Is it possible you have run out of heap memory? Which heap implementation are you using? heap_1, heap_2, heap_3, heap_4 or heap_5? https://www.freertos.org/a00111.html

Do you have a malloc failed hook defined? https://www.freertos.org/a00016.html

There was a lot wrong with the code, especially this line:

-    lBytesReceived = FreeRTOS_recv( xListeningSocket, cRxedData, BUFFER_SIZE, 0 );
+    lBytesReceived = FreeRTOS_recv( xConnectedSocket, cRxedData, BUFFER_SIZE, 0 );

The listening socket is only needed when callingFreeRTOS_accept().
The reading and writing must take place with the connected socket.

I re-wrote the server to do the following:

  • Wait for a connection
  • Wait at most 10 seconds for at most 1500 bytes
  • Send back what has been received
  • Start a graceful closure of the connection
  • Close the client socket
  • Go to start

The main loop does not have a break any more, so the code after the loop will never be reached.

tcp_server_task.c (4.6 KB)
And a PCAP of the conversation: tcp_server.zip (537 Bytes)

Hi.

Thank you for your help.

Richard Barry : I am sorry, I did not mention that it is not a malloc fail as I am using a failed hook and my program does not go into that function.

Hein Tibosch : My issue was indeed the wrong use of socket. I checked replacing xListeningSocket with xConnectedSocket and my code is working. I will take time to analyze your reply (what you re-wrote) and FreeRTOS+TCP.

I don’t understand why using two sockets. I thought Berkeley sockets used only one socket.

Thank you for your help again.

Have a nice day.
FGU

What you remember is maybe a client socket. You can use it to connect to a server socket.
A web browser is using single client sockets to connect to a web server.
A web server has one socket in listening mode ( to port 80 ), and several connected sockets that were obtained with accept().

Does the example work for you now?

Yes it’s working thank you.

FGU