Possible deadlock in "FreeRtos_accept"

If “ipconfigTCP_HANG_PROTECTION” is set to 1 and there is no network activity while the socket is in “eSYN_RECEIVED” state (in our case by debugging the remote peer site), the socket will be closed after “ipconfigTCP_HANG_PROTECTION_TIME” has elapsed. This causes a deadlock because the socket isn’t able to accept any request anymore. I already added a small amount of lines (in “prvTCPStatusAgeCheck” of “FreeRTOS_TCP_IP.c”) to solve this problem:
/* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. /
if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
{
// HS 2020-04-27 >>>
if( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED )
{
#if( ipconfigHAS_DEBUG_PRINTF == 1 )
{
FreeRTOS_debug_printf( ( “Inactive socket rem %lXip: %u status %s: listen again\r\n”,
pxSocket->u.xTCP.ulRemoteIP,
pxSocket->u.xTCP.usRemotePort,
FreeRTOS_GetTCPStateName(( UBaseType_t)pxSocket->u.xTCP.ucTCPState) ) );
}
#endif /
ipconfigHAS_DEBUG_PRINTF */

                // Move to eTCP_LISTEN because RemoteIP / RemotePort normally will change!
                vTCPStateChange( pxSocket, eTCP_LISTEN ); 
            }
            else
            {

// <<< HS 2020-04-27

Hello Hubert, is this socket using the re-use option?

Hello Hein, yes the re-use option is set always in this application to save resources because there are up to 10 sockets open but each of them must be restricted to be connected by one client only.

Hubert, I had to try it out my self to see exactly what happens. I was able to replicate it.

With normal sockets ( non-reusable ), there is no problem. When a new connection times out in the SYN phase, the newly created socket is closed without notice. The parent socket is not involved in this.

When using the socket option FREERTOS_SO_REUSE_LISTEN_SOCKET, the parent- and the child-socket are the same instance. That is cheaper: it saves a socket.

Normally, the cycle of a re-usable socket is as follows:

    parent_socket = FreeRTOS_socket();
    FreeRTOS_bind( parent_socket );
    FreeRTOS_listen( parent_socket );
    for( ;; )
    {
        child_socket = FreeRTOS_accept( parent_socket );
        if( child_socket == FREERTOS_INVALID_SOCKET )
        {
            /* This is an error. Socket must be closed and reopened. */
        }
        else if ( child_socket == NULL )
        {
            /* This is a time-out, call FreeeRTOS_accept() again. */
            continue;
        }
        else /* child_socket == parent_socket */
        {
            for( ;; )
            {
                /* Do i/o with client until disconnected. */
            }
        }
        /* correction: in an earlier version I wrote 'child_socket' here below. */
        FreeRTOS_closesocket( parent_socket );
        child_socket = NULL;
        parent_socket  = NULL;
        /* Now create the socket again: socket()/bind()/listen() */
    }

When calling FreeRTOS_accept(), the parent socket should have the status eTCP_LISTEN. Now suppose that a connection timed out during the SYN phase, then the parent socket will be given the status eCLOSED.

If you check the status, you can avoid the problem:

    if( FreeRTOS_connstatus( parent_socket ) == eCLOSED )
    {
        /* Indicate there was an error and the socket must be re-created. */
        child_socket = FREERTOS_INVALID_SOCKET;
    }
    else
    {
        child_socket = FreeRTOS_accept( parent_socket );
    }
    if( child_socket == FREERTOS_INVALID_SOCKET )
    /* etc, see here above. */

Note that the duration of FreeRTOS_accept() is limited by the socket’s READ time-out ( FREERTOS_SO_RCVTIMEO ). Give it a reasonable timeout, because you will have to check the socket status regularly.

I could change the library for this, but I think that the above is a good work-around. Please let us know.

Hein,

I know. My pice of code was only for information how I solved it and I wanted doing some support to FreeRTOS+TCP.

I answered by mail to be able to add a picture…

The CPU of the controller is a replacement of an old PLC and don’t use a microprocessor - it’s an microprogrammed RALU based dual core multitasking CPU implemented in a SmartFusion2 with a lot of extensions to the original system (I’m granted to do further development etc. by the original manufactor - SIEMENS)

The FreeRTOS+TCP is used with the CM3 in the SF2.

best regards,

Hubert Sack

SMD electronics GmbH

1 Like