FreeRTOS+TCP labs - FreeRTOS_accept not waking up thread on connect.

elgroves wrote on Wednesday, February 18, 2015:

I’ve ported FreeRTOS 8.1.2 to the TI TM4C1294NCPDT. I’ve configured FreeRTOS+TCP labs (141019) and written an interface driver for the TM4C part.

I’m writing an HTTP server that has a thread listening for inbound TCP connections. Once the connection is received, the new socket will be passed to a thread pool via a queue and handled there. My problem is that the FreeRTOS_accept call doesn’t wake up the thread. I can see in Wire Shark that the TCP stack takes the connection (SYN, ACK, HTTP request), but the handling thread is never woken up to handle it, so it just remains connected until some other event closes the socket.

If I configure the listening socket w/ a non-zero FREERTOS_SO_RCVTIMEO, the accept call returns. If no connection was found, I retry. If a connection is found, I pass it along and it is handled correctly, data flows, and all is well. But I’d prefer the accept call wake up my thread when a connection is received to reduce both latency and un-needed cycles. Is this not supported in the current version of FreeRTOS+TCP?

I am very ready to acknowledge that I may have mis-configured FreeRTOS or FreeRTOS+TCP.

My connection accepting thread:

void http_server(void * params)
{
	static const TickType_t xReceiveTimeOut = 1000 / portTICK_RATE_MS; // portMAX_DELAY;

	xSocket_t client_socket;
	struct freertos_sockaddr bindAddress;
	struct freertos_sockaddr clientAddress;

	socklen_t size = sizeof(clientAddress);

	(void) params;

	server.listen_socket = FreeRTOS_socket(FREERTOS_AF_INET,
			FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);

	configASSERT(server.listen_socket != FREERTOS_INVALID_SOCKET);

	FreeRTOS_setsockopt(server.listen_socket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof(xReceiveTimeOut));

	bindAddress.sin_port = (uint16_t) server.settings.listen_port;
	bindAddress.sin_port = FreeRTOS_htons(bindAddress.sin_port);

	FreeRTOS_bind(server.listen_socket, &bindAddress, sizeof(bindAddress));

	FreeRTOS_listen(server.listen_socket, 20);

	for (;;)
	{

		client_socket = FreeRTOS_accept(server.listen_socket, &clientAddress, &size);

		if (client_socket == FREERTOS_INVALID_SOCKET
				|| client_socket == NULL)
		{
			continue;
		}

		xQueueSendToBack(server.rx_sockets_queue, &client_socket, 1000 /portTICK_PERIOD_MS); //portMAX_DELAY);
	}
}

Thanks for any help!

rtel wrote on Wednesday, February 18, 2015:

[we actually have a simple http server - it should have been released by now - but we have been busy :o) ]

Did you see the example implemented by the SimpleTCPEchoServer.c file in the download? I think that is doing something similar to what you want, albeit with a different protocol (echo rather than HTTP). The part that is equivalent looks like this:

static void prvConnectionListeningTask( void *pvParameters )

{
struct freertos_sockaddr xClient, xBindAddress;
xSocket_t xListeningSocket, xConnectedSocket;
socklen_t xSize = sizeof( xClient );
static const TickType_t xReceiveTimeOut = portMAX_DELAY;
const BaseType_t xBacklog = 20;
xWinProperties_t xWinProps;

/* Just to prevent compiler warnings. */
( void ) pvParameters;

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

configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

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

/* Fill in the buffer and window sizes that will be used by
the socket. /
xWinProps.lTxBufSize = 6 ipconfigTCP_MSS;
xWinProps.lTxWinSize = 3;
xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS;
xWinProps.lRxWinSize = 3;

/* Set the window and buffer sizes. /
FreeRTOS_setsockopt( xListeningSocket,
0,
FREERTOS_SO_WIN_PROPERTIES,
( void ) &xWinProps,
sizeof( xWinProps ) );

/* Bind the socket to the port that the client task will send to, then
listen for incoming connections. */
xBindAddress.sin_port = tcpechoPORT_NUMBER;
xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
FreeRTOS_listen( xListeningSocket, xBacklog );

/* Create the clients that will connect to the listening socket. */
prvCreateWindowsThreadClients();

for( ;; )
{
/* Wait for a client to connect. */
xConnectedSocket = FreeRTOS_accept( xListeningSocket,
&xClient,
&xSize );

configASSERT( xConnectedSocket <span style="color: #333333">!=</span> FREERTOS_INVALID_SOCKET );

<span style="color: #888888">/* Spawn a task to handle the connection. */</span>
xTaskCreate( prvServerConnectionInstance, 
      <span style="background-color: #fff0f0">&quot;EchoServer&quot;</span>, 
      usUsedStackSize, 
      ( <span style="color: #333399; font-weight: bold">void</span> <span style="color: #333333">*</span> ) xConnectedSocket, 
      tskIDLE_PRIORITY, 
      <span style="color: #007020">NULL</span> );

}
}

Basically it should work. If that does not help I will defer to our TCP expert.

Regards.

rtel wrote on Wednesday, February 18, 2015:

By the way please ensure to post your work (just the FreeRTOS+TCP part if the rest is confidential) to the FreeRTOS Interactive site when you are happy it is working.

Regards.

elgroves wrote on Wednesday, February 18, 2015:

Thanks for getting back to me so quickly!

I did see a note that an HTTP server was in the works, but I didn’t want to wait to find out what support it included. I’m developing a flexible server that can serve static resources from internal memory (.html, .css, .js, etc.), and process get/post/put/delete requests in CGI handlers as well.

I referenced the example in SimpleTCPEchoServer.c quite a bit when I was writing the connection listener. I don’t see a material difference from my implementation up to the accept call, other than the Windowing options. I’ve since included the missing parts in the code and I am still seeing the same behavior: connection accepted by the server, data sent by the client, no response from the server, the listening thread is never woken.

I’d be glad to contribute some of my code! What precisely do I need to post, and what can I keep confidential? I’d like to keep my server code confidential until it’s a bit more completed.

Thanks again!

heinbali01 wrote on Friday, February 20, 2015:

Hi,

What precisely do I need to post, and what can I keep confidential?

What you could share is the interfacing between the hardware drivers and +TCP.
Normally this code would be put in a file like:

FreeRTOS-Plus-TCP/portable/NetworkInterface/TM4C1294/NetworkInterface.c

I tried-out you http_server() code but it does work properly:

static void http_handler( void * params )
{
    xSocket_t xSocket = NULL;
    for (;;)
    {
        clearWdt ();

        if( ( xSocket != FREERTOS_INVALID_SOCKET ) && ( xSocket != NULL ) )
        {
        char buffer[80];
            BaseType_t rc = FreeRTOS_recv( xSocket, buffer, sizeof buffer, 0 );
            if (rc != 0)
                printf("recv %ld bytes\n", rc);
            if (rc < 0) {
                FreeRTOS_closesocket( xSocket );
                xSocket = NULL;
            }
        }
        else if( xQueueReceive( server.rx_sockets_queue, (void *)&xSocket, 1000 ) )
        {
            printf("recv socket\n");
        }
    }
}

When a connection closes, the logging shows recv -128 bytes which is the error:

  #define FREERTOS_ERRNO_ENOTCONN  128 /* Socket is not connected */

Please note that all settings done with FreeRTOS_setsockopt() will be inherited by the child-sockets. That includes all timings and buffer sizes.

In some cases a connection may have a very short life, like 25 ms to receive 50 KB. The handling task may wake-up after the connection has gone. The data can still be read though.

If your still find the above problem, please drop an email to Richard (see FreeRTOS’ main page). We’ll send you the latest release of +TCP.

Regards.

hmf55 wrote on Thursday, March 05, 2015:

Hi,
I’ve got the simmilar if not the same problem.
“FreeRTOS_accept” never commes back, also WireShark shows no outgoing messages nor
any ACKs.

I’ve implementented the zero copy EDMAC for the RX63N. I think its running as far
as I could send and receive UDP packets.

My code looks like the one above, except that “prvCreateWindowsThreadClients();”

Is this the missing link? Where could I get/find it?

BTW: I’m also eager for a webserver. At the moment I’ve planned to rewrite
the A.Dunkels-Code to get rid of those magic PT macros.

Tanks.

heinbali01 wrote on Thursday, March 05, 2015:

Regarding: FreeRTOS_accept doesn’t work:

When you bind() the socket to a port, are all values in network byte-order, like in:

    /* sin_addr is not yet use, keep it zero for now. */
    bindAddress.sin_addr = 0ul;
    /* If '80' is your server port... */
    bindAddress.sin_port = FreeRTOS_htons( 80 );
    FreeRTOS_bind(pxServerSocket, &bindAddress, sizeof(bindAddress));

Is the IP-task running fine?

Did you give some reasonable value to the socket options FREERTOS_SO_RCVTIMEO and FREERTOS_SO_SNDTIMEO ? Or else, did you set:

#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME  ( 10000 )
#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME     ( 10000 )

or any other value?

Can you set a break in the code? Like here for instance:

static void prvIPTask( void *pvParameters )
{
    case eNetworkRxEvent:
        prvHandleEthernetPacket( ( xNetworkBufferDescriptor_t * )
            ( xReceivedEvent.pvData ) );
        break;

Can you assert that there are always enough Network Buffers available? Does pvPortMalloc() ever return NULL?

Edit:
How much is enough? I would say always at least 3 or 4 Network Buffer.

Regards.

ewnert wrote on Monday, October 19, 2015:

I now this thread is a bit old but it is the only one I have found addressing this problem.

I had the exact same problem as described in the first post. The TCP connection is made and I can see in WireShark that SYN and ACK is transmitted and received.

After hours of investigating I tried increasing the value of ipconfigEVENT_QUEUE_LENGTH and all of a sudden it started working. I assume that the queue was full so the connection event did not reach the FreeRTOS_accept().

I had the constant ipconfigEVENT_QUEUE_LENGTH set to ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 which is the recommended minimum value. I increased it to ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 20 and FreeRTOS_accept() started working.

heinbali01 wrote on Tuesday, October 20, 2015:

Hi Carl,

thanks for letting this know.

xNetworkEventQueue’ is the Queue that hold the messages for the IP-task. It should never run out of space.

Some NetworkInterface.c files already had the following check in their MAC task:

    {
        uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
        if( uxLastMinBufferCount != uxCurrentCount )
        {
            /* The logging produced below may be helpful
            while tuning +TCP: see how many buffers are in use. */
            uxLastMinBufferCount = uxCurrentCount;
            FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
                uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
        }
    }

It would be good to monitor the space in the ‘xNetworkEventQueue’ as well.

Without changing anything to FreeRTOS_IP.c you can define this macro in your ‘FreeRTOSIPConfig.h’:

    extern UBaseType_t uxQueueMinimumSpace;
    #define iptraceNETWORK_EVENT_RECEIVED( EventType ) \
    { \
        if( xReceivedEvent.eEventType != eNoEvent ) \
        { \
        UBaseType_t uxCount; \
      \
             uxCount = uxQueueSpacesAvailable( xNetworkEventQueue ); \
            if( uxQueueMinimumSpace > uxCount ) \
            { \
                uxQueueMinimumSpace = uxCount; \
            } \
        } \
    }

Declare and initialise it as follows:

    /* Define and initialise 'uxQueueMinimumSpace' */
    UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;

and finally add some logging:

    if( uxLastLowCount != uxQueueMinimumSpace )
    {
        uxLastLowCount = uxQueueMinimumSpace;
        FreeRTOS_printf( ( "Lowest queue space: %lu\n",
            uxLastLowCount ) );
    }

Regards.

elgroves wrote on Wednesday, October 28, 2015:

Hein, I’d like to thank you for your support and also to apologize for not participating more in this conversation. The project ended up being pre-empted, and I have just been able to get back to it after having lost all of my source code. I’m having different issues while re-implementing the Network Interface driver, but I won’t attempt to address them here.

Thanks again for your hard work.