Describe the bug
A listening socket can have multiple pending established child connections waiting for FreeRTOS_accept().
If the child currently referenced by the listener (the first pending child connection) is reset before it is accepted, FreeRTOS clears the reference but does not select another established child. FreeRTOS_accept() then returns NULL, even though another valid child is still in eESTABLISHED.
If no new connection arrives, the remaining child will not be rescanned. The connection can remain stuck, occupy a listener capacity slot, and leave the client blocked.
Target
- Development board: QEMU MPS2, using the official
FreeRTOS_Plus_TCP_Echo_Qemu_mps2 demo
- Instruction Set Architecture: 32-bit Armv7-M, Cortex-M3, Thumb-2, little-endian, no hardware FPU (-machine mps2-an385 -cpu cortex-m3; compiler flags -mcpu=cortex-m3 -mthumb)
- IDE and version: None. command-line build using GNU Make
- Toolchain and version: Arm GNU Toolchain 15.3.Rel1: arm-none-eabi-gcc 15.3.1 20260627 (Build arm-15.149)
Host
- Host OS: macOS
- Version: macOS 26.5.1 (Build 25F80)
To Reproduce
- Use the official
FreeRTOS_Plus_TCP_Echo_Qemu_mps2 demo.
- Replace the demo TCP task with the attached
poc.c.
- Use the attached
FreeRTOSIPConfig.h.
- Run:
The client performs these steps:
- Client A connects.
- Client B connects.
- Client A closes with an RST.
- Client B sends one byte and waits for a reply.
- The server calls non-blocking
FreeRTOS_accept().
Relevant output:
A and B connected; B source port: 60069
A reset; B sent one byte and is now blocked in recv()
Socket 12345 -> [10.0.2.2]:60068 State eSYN_RECEIVED->eESTABLISHED
Socket 12345 -> [10.0.2.2]:60069 State eSYN_RECEIVED->eESTABLISHED
Socket 12345 -> [10.0.2.2]:60068 State eESTABLISHED->eCLOSED
POC_RESULT: BUG: accept returned no connection
TCP 12345 0ip : 0 0/0 eTCP_LISTEN 10000 0 1/2
TCP 12345 a000202ip :60069 1/0 eESTABLISHED 5658 11648
POC_PROOF: client B is still blocked after accept returned NULL
The output shows that:
- A and B both reached
eESTABLISHED.
- A, using source port
60068, was reset and closed.
FreeRTOS_accept() returned no connection.
- B, using source port
60069, was still in eESTABLISHED.
- The listener still reported one child in its status report:
1/2.
Therefore, the server still has a valid pending child, but the application cannot obtain it through FreeRTOS_accept().
Expected behavior
After A is reset, FreeRTOS_accept() should find and return B. Removing one pending child should not make another established child unreachable.
Screenshots
Not applicable.
Additional context
Server side reproducer: poc.c
Client side reproducer: client.py
The listener appears to keep only one pending child in pxPeerSocket. When that child is removed, the pointer is cleared, but another established child is not filled into the slot.
A possible fix:
- When the child pointed by
listener->pxPeerSocket is removed, clear the closing child’s accept flags.
- Rescan the listener’s remaining children.
- If another established child is ready, assign it to
listener->pxPeerSocket.
- Set the accept event and wake any task waiting in
FreeRTOS_accept().
The closing child’s flags should be cleared before the rescan so that the closing child cannot be selected again.
Describe the bug
A listening socket can have multiple pending established child connections waiting for
FreeRTOS_accept().If the child currently referenced by the listener (the first pending child connection) is reset before it is accepted, FreeRTOS clears the reference but does not select another established child.
FreeRTOS_accept()then returnsNULL, even though another valid child is still ineESTABLISHED.If no new connection arrives, the remaining child will not be rescanned. The connection can remain stuck, occupy a listener capacity slot, and leave the client blocked.
Target
FreeRTOS_Plus_TCP_Echo_Qemu_mps2demoHost
To Reproduce
FreeRTOS_Plus_TCP_Echo_Qemu_mps2demo.poc.c.FreeRTOSIPConfig.h.make reproduceThe client performs these steps:
FreeRTOS_accept().Relevant output:
The output shows that:
eESTABLISHED.60068, was reset and closed.FreeRTOS_accept()returned no connection.60069, was still ineESTABLISHED.1/2.Therefore, the server still has a valid pending child, but the application cannot obtain it through
FreeRTOS_accept().Expected behavior
After A is reset,
FreeRTOS_accept()should find and return B. Removing one pending child should not make another established child unreachable.Screenshots
Not applicable.
Additional context
Server side reproducer: poc.c
Client side reproducer: client.py
The listener appears to keep only one pending child in
pxPeerSocket. When that child is removed, the pointer is cleared, but another established child is not filled into the slot.A possible fix:
listener->pxPeerSocketis removed, clear the closing child’s accept flags.listener->pxPeerSocket.FreeRTOS_accept().The closing child’s flags should be cleared before the rescan so that the closing child cannot be selected again.