FreeRTOS_FD_SET on a Listening TCP Socket
I wrote a small web server and have it running on another platform(os and stack).
I’ve ported it into my embedded application (FreeRTOS + IP).
I create a listen socket.
I create a socket_set.
I use FreeRTOSFDSET to set an eSELECT_READ to the listen socket.
I then FreeRTOS_select to wait for a connection on the listen socket.
Should this work with the FreeRTOS_IP stack? I’m assuming an incoming connection is treated as a read on the listen socket thereby enabling the select to react.
Your on-line documentation shows a web_server thread that simply listens for a connection and then spawns after the accept. I’m hoping I don’t have to create tasks for every connection and can manage them all in one task.
Thanks for any insight into this.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
I traced a TCP message into the stack.
The stack created a new socket based on the listen but I saw no process to then set an event bit on the listening socket so the select would respond.
I probably missed the call (I’m hoping) and it’s just something I missed that is not causing the select to respond to the READ on the listen socket.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
It is not clear from your post – are you saying you tried this and it
didn’t work, or just asking if it should work?
If you tried it and it didn’t work then there is a known issue whereby
you have to ensure the priority of the task running the TCP/IP stack is
higher than the priority of any tasks using the TCP/IP stack, and lower
than any deferred interrupt handling tasks.
If you are asking if it should work then I believe the answer is yes.
All the connections in the FTP and [basic] HTTP server examples in the
labs download all run in the same task, using a call to
FreeRTOSselect(). You will find the code in
FreeRTOS-PlusSourceFreeRTOS-Plus-TCPprotocolsFreeRTOSTCP_server.c
FreeRTOS_FD_SET on a Listening TCP Socket
I’m stating it does not work.
Here are my priority settings … the stack is higher than the Web_Server.
Select is firing — return based on timeout.
~~~
// FreeRtos set up with 15 task priorities … see config
// priorities from 0 (idle) to 14
define SPITASKPRIORITY ( configMAX_PRIORITIES – 1 ) // max priority
define AudioTASKPRIORITY ( configMAX_PRIORITIES – 2 ) // max priority
define EmacRCVTASKPriority ( configMAXPRIORITIES – 3 )
//#define ipconfigIPTASKPRIORITY (configMAX_PRIORITIES – 4) in freertos configdefine MainProcessTASKPRIORITY ( configMAX_PRIORITIES – 5 )
define WebServerTASKPRIORITY (4)
define UDPDebugTASK_PRIORITY (3)
define UDPDebuggerTASK_PRIORITY (3)
// #define configTIMERTASKPRIORITY ( 2 ) in freertos configdefine DisplayTASKPRIORITY ( 1 )
~~~ Any suggestions?FreeRTOS_FD_SET on a Listening TCP Socket
I checked my code to your and I can’t see anything.
Do you notice something I’ve done incorrectly?
~~~
vTaskDelay(100 / portTICKPERIODMS); } /* Set a time out so accept() will just wait for a connection. */ FreeRTOS_setsockopt( ListenSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
while(1)
{
/* Create a TCP socket. */
ListenSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
if( ListenSocket != FREERTOS_INVALID_SOCKET)
break;
TryAgain:vTaskDelay(100 / portTICKPERIODMS); } /* Set a time out so accept() will just wait for a connection. */ FreeRTOS_setsockopt( ListenSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
ZeroMemory(&server_addr, sizeof(server_addr));
server_addr.sin_port = FreeRTOS_htons( ListenPort );
server_addr.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used
// Bind the address to the socket.
if(FreeRTOS_bind(ListenSocket, &server_addr, sizeof( server_addr ) ) == -1 )
{
FreeRTOS_closesocket( ListenSocket );
ListenSocket = FREERTOS_INVALID_SOCKET;
goto TryAgain;
}
UDP_Debug_Printf1("Socket created and Bind.n");
while(1)
{
SocketSet2Select = FreeRTOS_CreateSocketSet();
if( SocketSet2Select)
break;
vTaskDelay(100 / portTICK_PERIOD_MS);
}
//Listen to incoming connections
r = FreeRTOS_listen(ListenSocket , MaxSessions);
// add listen to socket set
FreeRTOS_FD_SET(ListenSocket, SocketSet2Select, eSELECT_READ);
//Accept and incoming connection
UDP_Debug_Printf1("Waiting for incoming connections...n");
while(1)
{
/* loop through list of open sessions looking for work */
for(i = 0; i < MaxSessions; i++)
{
if (Sessions[i].S == FREERTOS_INVALID_SOCKET)
{
continue;
}
/* If socket is reading, load for a select */
if(Sessions[i].State == WS_HEADER)
{
if((Sessions[i].HasBeenAddedToSetSelect & 1) == 0) // no read in place
{
Sessions[i].HasBeenAddedToSetSelect |= 1;
FreeRTOS_FD_SET(Sessions[i].S, SocketSet2Select, (eSELECT_READ | eSELECT_EXCEPT));
}
}
else if(Sessions[i].HasBeenAddedToSetSelect & 1) // in select - remove it
{
Sessions[i].HasBeenAddedToSetSelect &= ~1;
FreeRTOS_FD_CLR(Sessions[i].S, SocketSet2Select, (eSELECT_READ));
}
if(Sessions[i].Flags & WF_DataWasSentLookForComplete) //(Sessions[i].XmitBuf) || (Sessions[i].Flags & WF_BINARY))
{
if((Sessions[i].HasBeenAddedToSetSelect & 2) == 0) // no write in place
{
Sessions[i].HasBeenAddedToSetSelect |= 2;
FreeRTOS_FD_SET(Sessions[i].S, SocketSet2Select, (eSELECT_WRITE | eSELECT_EXCEPT));
}
}
else if(Sessions[i].HasBeenAddedToSetSelect & 2) // in select - remove it
{
Sessions[i].HasBeenAddedToSetSelect &= ~2;
FreeRTOS_FD_CLR(Sessions[i].S, SocketSet2Select, (eSELECT_WRITE));
}
}
TimeoutActive = 0;
/* See if any of the sockets have input or ready to send */
r = FreeRTOS_select(SocketSet2Select, (10000 / portTICK_PERIOD_MS)); // Blocks until activity
if(r < 0)
continue; // error
if(r == 0)
{
TimeoutActive = 1;
}
else
{
// check if new read on listen
if(FreeRTOS_FD_ISSET(ListenSocket, SocketSet2Select) & eSELECT_READ) // read on listen means new connection waiting
AcceptConnection();
}
~~~
FreeRTOS_FD_SET on a Listening TCP Socket
The example is calling:
FreeRTOSFDSET( xSocket, xSocketSet, eSELECTREAD | eSELECTEXCEPT );
What happens if you use eSELECT_EXCEPT too? Maybe the socket is getting
disconnected?
FreeRTOS_FD_SET on a Listening TCP Socket
I use FreeRTOSFDSET to set an eSELECT_READ to the listen socket.That is correct, a new incoming connection is treated as a READ event. A successful outgoing connection would cause a WRITE event. As Richard stated, in the current release of +TCP, there is a problem with
FreeRTOS_accept()
if the IP-task runs at a low priority.
Your configured priorities seem to be OK.
If you want, publish some code of your web server. Or, alternatively, you can contact us directly (at freertos.org) and we’ll find the cause of the problem.
Regards.
FreeRTOS_FD_SET on a Listening TCP Socket
Hein:
I posted the code … 2 posts up.
See anything?
Thanks in advance for any insight.
FreeRTOS_FD_SET on a Listening TCP Socket
I added eSELECT_EXCEPT per your suggestion — still not firing
~~~
FreeRTOSFDSET(ListenSocket, SocketSet2Select, (eSELECTREAD | eSELECTEXCEPT ));
~~~
FreeRTOS_FD_SET on a Listening TCP Socket
Hi Joe,
Our messages crossed. Tomorrow I will look at the source code that you published.
FreeRTOS_FD_SET on a Listening TCP Socket
This statement was made above:
If you tried it and it didn’t work then there is a known issue whereby
you have to ensure the priority of the task running the TCP/IP stack is
higher than the priority of any tasks using the TCP/IP stack, and lower
than any deferred interrupt handling tasks.
Can you explain the BOLD section better?
I have a ENET Message Received task that feeds the stack. THAT task is higher priority than your stack priority … is THAT what is meant by the bold statement? If so … I’m good there also.
FreeRTOS_FD_SET on a Listening TCP Socket
A deferred interrupt handler is a task that is used to perform what
would otherwise be performed in an interrupt service routine.
Often an Ethernet interrupt wants to allocate a buffer. Depending on
the buffer allocation scheme it might be that the buffer cannot be
allocated from the interrupt, so the interrupt handler just unblocks a
high priority task, and the buffer allocation and other interrupt
processing is then performed in the task.
The idea is a deferred interrupt handling task is blocked to wait for an
interrupt then, when an interrupt occurs, the interrupt handler unblocks
the task that is waiting and returns directly to that task so the
interrupt processing occurs contiguous in time just as if it had been
performed in the interrupt itself. (the interrupt handler interrupts a
lower priority application task, and returns to a higher priority
deferred interrupt handler task.
Search for ‘deferred’ on the following page:
http://www.freertos.org/FreeRTOS-Plus/FreeRTOSPlusTCP/EmbeddedEthernetPorting.html
FreeRTOS_FD_SET on a Listening TCP Socket
That’s what I thought — That is what I have in stated in the post prior to your reply .. so I’m OK there.
Thanks for further explaining.
FreeRTOS_FD_SET on a Listening TCP Socket
Hein:
Have you had a chance to look over the code I posted to help me identify the issue?
Thanks.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
I’m using the latestest release of the stack.
When did Select processing switch from using a queue to event bits?
From a user perspective, it’s pretty simple and straight forward.
I can’t see anything wrong with my user code.
As I posted earlier, I can trace a TCP connect message coming into the stack and it gets processed by the waiting listen socket. The stack creates a new socket but not sure what you do with it since I’m never notified. I was NOT able to see any code that would process event bits based on that listen action.. that process may be hard to trace as your comments in the stack suggest you are posting messages within the stack to handle things at a later time … I’m not to the point where I can absolutly follow that.
Can you please confirm that Select using event bits has been verified to work?
Thanks.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
I found the issue.
At this ime, I would call it a stack issue related to conflicting config options.
If the user has enabled config setting (as I had) ipconfigTCPHANGPROTECTION, the the new socket created by the listen is NOT assigned to the listening sockets’s “pxPeerSocket”.
A select on a listening socket for eSELECT_READ is not capable because the listening’s socket “pxPeerSocket” is not set.
Root-cause of my issue … FreeRTOSIPConfig.h CAN NOT have option “ipconfigTCPHANGPROTECTION” enabled and expect select to respond to a “eSELECT_READ” on a listening socket.
Dis-Abled option ipconfigTCPHANGPROTECTION — it works as expected.
So, I would suggest you have an issue with the implementation of option ipconfigTCPHANGPROTECTION as it breaks the select capability.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
Update:
There is NO issue with option ipconfigTCPHANGPROTECTION as I stated above.
Option ipconfigTCPHANGPROTECTION delays the Listen Select from firing until the connection is completed. By removing the ipconfigTCPHANGPROTECTION, the Listen Select will fire with 2 of three 3 connection hand-shakes complete (after the stack replies with SYN+ACK). The ipconfigTCPHANGPROTECTION prevents the Listen Select from firing until the stack receives the ACK from the client.
My issue was I was NOT receiving the ACK reply because of another issue: see post
Stack is GREAT!!!
User had the issue.
Joe
FreeRTOS_FD_SET on a Listening TCP Socket
About ‘ipconfigTCPHANGPROTECTION’ : I don’t think there is an issue with the anti-hanging protection. There is indeed a difference in behaviour, and for good reasons:
~~~~
if( ipconfigTCPHANGPROTECTION != 0 )
/* You will only see a new socket as soon as the 3-way hand-shake is ready. */
else
/* You will receive a new socket immediately after its creation,
i.e. after the first SYN. */
endif
~~~~ With anti-hanging protection, the IP-stack takes care of the new socket until it is fully connected. In case it fails, the socket will be closed by the stack. It will have a timer running, so incase the peer dies, the socket will be closed by the stack. Without the anti-hanging protection, the application is made responsible for closing the new socket in case the 3-way handshake was not successful. With ‘ipconfigTCPHANGPROTECTION == 0′ your select() will return a READ event, and accept() does succeed, but the 3-way handshake is still failing. Later we found why the handshake didn’t work: there was a misconception aboutxNetworkInterfaceOutput()
should work.
~~~~
BaseTypet xNetworkInterfaceOutput(
NetworkBufferDescriptort * const pxNetworkBuffer,
BaseType_t xReleaseAfterSend )
~~~~
If xReleaseAfterSend
is false, it means that the NetworkBuffer is passed as read-only. Once the function xNetworkInterfaceOutput()
returns, the NetworkBuffer may not be accessed any more.
If xReleaseAfterSend
is true, the ownership of the NetworkBuffer is passed to the driver and the driver may (must) release the buffer after using it. It may still be accessed after returning from the function.
A driver that works with so-called zero-copy transmissions will define:
~~~~
define ipconfigZEROCOPYTX_DRIVER ( 1 )
~~~~ These drivers will always be called withxReleaseAfterSend
== true. The Network Buffers will be passed to DMA. When DMA is ready transmitting a buffer, it shall be released by the driver.