How to end a TCP client task?

hannes23 wrote on Monday, June 03, 2019:

Hi all,
I’m looking for an idea how to stop / end / kill a task which stucks in a possibly long or endlos lasting wait situation.
At my embedded system FreeRTOS-TCP creates several TCP client tasks by a listener task. The embedded system acts as a server, which is connected to a PC via Ethernet/TCP.
When now the PC client fails or the connection is broken otherwise, the client-task on the embedded server possibly still runs and is stuck in a send or receive routine with big timeouts, or waits otherwise for a situation that will never happen.
So how could such ghost-tasks be ended or killed when after a failing situation the PC program us restarted.
The system works of course also without ending these, now useless, tasks, but the number of TCP tasks is normally limited and will soon reach this limit.
I hope I could explain my problem and am glad, if someone can help with ideas.

Greetings

heinbali01 wrote on Monday, June 03, 2019:

HI Johannes,

First: I would let these tasks take control of the situation, let the task decide when a connection is considered dead.

You can control the maximum blocking time per API. That is documented on freertos.org/tcp

#define FREERTOS_SO_RCVTIMEO     ( 0 ) /* Used to set the receive time out. */
#define FREERTOS_SO_SNDTIMEO     ( 1 ) /* Used to set the send time out. */

FreeRTOS+TCP has mechanisms to detect an orphaned connection, which happens when the peer has left without a graceful closure.

/* Include support for TCP hang protection.  All sockets in a connecting or
disconnecting stage will timeout after a period of non-activity. */
#define ipconfigTCP_HANG_PROTECTION        ( 1 )
#define ipconfigTCP_HANG_PROTECTION_TIME   ( 30 )

/* Include support for TCP keep-alive messages. */
#define ipconfigTCP_KEEP_ALIVE             ( 1 )
#define ipconfigTCP_KEEP_ALIVE_INTERVAL    ( 20 ) /* in seconds */

If possible, it is even better to implement this protection at a higher level: send a are-you-alive (AYA) message at regular intervals to check if the connection is still OK.
These messages only have to be sent as long as there is no other traffic.

I think there is no need to detect and kill ghost tasks: make them responsible for their connections and let them kill them selves when done.

Security: I sometimes do have a (software) watchdog that must be touched regularly by all tasks, e.g. every minute. But when that watchdog goes off, it’s like an exception: it will cause a reset of the CPU, and the event will be reported.

If you have plenty of resources, it’s fine to handle one socket per task. But if you have little RAM, you can use one of the many techniques to handle a who set of socket within one task. Think of:

/* Use FreeRTOS_select() */
#define ipconfigSUPPORT_SELECT_FUNCTION    1

/* Use call-backs */
#if ipconfigUSE_CALLBACKS == 1
    #define FREERTOS_SO_TCP_CONN_HANDLER  (  6 )  /* Install a callback for (dis) connection events */
    #define FREERTOS_SO_TCP_RECV_HANDLER  (  7 )  /* Install a callback for receiving TCP data */
    #define FREERTOS_SO_TCP_SENT_HANDLER  (  8 )  /* Install a callback for sending TCP data */
    #define FREERTOS_SO_UDP_RECV_HANDLER  (  9 )  /* Install a callback for receiving UDP data */
    #define FREERTOS_SO_UDP_SENT_HANDLER  ( 10 )  /* Install a callback for sending UDP data */
#endif /* ipconfigUSE_CALLBACKS */

/* Connect each socket with a semaphore. */
#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
    #define FREERTOS_SO_SET_SEMAPHORE    ( 3 )        /* Used to set a user's semaphore */
#endif

The above is all documented on freertos.org/tcp and often discussed on this forum.

hannes23 wrote on Tuesday, June 04, 2019:

Thank you very much Hein, for your detailed advice.
To remove any client-ghost-tasks, I think I will start with changing the timeouts and enable the keep-alive mechanism.