Fri 05 Aug 2011 10:37:32 AM UTC, original submission:
I noticed this faulty behaviour when I was trying to "put" a file from a Windows FTP client to a FTP server using version 1.3.0 of the lwIP stack. Sometimes the last bytes in the file were missing.
The FTP server would call lwip_recvfrom which again would call netconn_recv.
In this case the file to be transferred was 52228 bytes long and the tcp packets eache contained 536 bytes with the last one containing only 236 bytes (97 * 536 + 236).
By instrumenting the lwip_recvfrom code I could see that most of the calls to netconn_recv returned just 536 bytes from one tcp packet. And when this one tcp packet contained a PUSH flag (I had WireShark running), the packet returned from the netconn_recv call also had the PUSH flag set.
But some of the calls to netconn_recv returned an aggregate of several tcp packets - I suspect because the receiving application had been busy doing other things. And if one of the tcp packets had the PUSH flag set, the flag was not set in the aggregate packet.
In this situation, the last 7 packets were aggregated (6 * 536 + 236). The last 256 byte packet had the PUSH flag set, but the aggregate packet returned from the netconn_recv call had no PUSH flag. So the lwip_recvfrom function would loop and call netconn_recv again, this time finding out that the connection had been closed, and returning 0 bytes.
I found out that the aggregate packet was a result of the last 7 packets being taken out of the out-of-sequence queue in the tcp_receive function. When a packet is inserted into the out-of-sequence queue, the tcp flags are remembered. But when the packets are taken out of the queue, the PUSH flag is forgotten.
I fixed the bug by adding a TF_GOT_PSH flag (tcp.h) which the tcp_receive function would set in the global recv_flags, if one of the packets in the out-of-sequence queue has the PUSH flag set.
In the tcp_input function, where the received packets (simple or aggregate) are returned from the tcp_process call, I added a check for the TF_GOT_PSH flag in the global recv_flags, and set the PUSH flag in the recv_data->flags accordingly before returning recv_data to the application.
I checked version 1.4.0 to see if this bug had already been fixed, but it didn't seem so.
I have attached sockets.c, tcp_in.c and tcp.h with my debug code and bug fix. The bug is named TD#10887.
|