[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-devel] [bug #43779] select(), close(), and TCP retransmission erro

From: Jonathan Portwood
Subject: [lwip-devel] [bug #43779] select(), close(), and TCP retransmission error
Date: Mon, 08 Dec 2014 14:33:18 +0000
User-agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36


                 Summary: select(), close(), and TCP retransmission error
                 Project: lwIP - A Lightweight TCP/IP stack
            Submitted by: jpbears1
            Submitted on: Mon 08 Dec 2014 02:33:17 PM GMT
                Category: sockets/netconn
                Severity: 3 - Normal
              Item Group: Faulty Behaviour
                  Status: None
                 Privacy: Public
             Assigned to: None
             Open/Closed: Open
         Discussion Lock: Any
         Planned Release: 
            lwIP version: 1.4.1



We ran across a fairly esoteric issue with the LwIP socket implementation.

The issue stems from using a TCP socket as a server. If the client sends data
to the server and is done, the client sends a "FIN" with the last packet. As
with all network stacks, in LwIP this results in select() notifying the
application of data on the socket and then a EOF on the server side draining
the socket. This is the correct behavior. In this situation you see this in
the debug:

tcp_receive: pcb->rttest 0 rtseq 6537 ackno 6538
tcp_receive: received FIN.

However,  in a very specifically crafted case where the packet right before
the FIN came from the client was dropped, a TCP retransmission must occur. 
The FIN packet was received and queued. Then the retransmitted packet is
received, and the FIN is dequeued. You see this in the debug log:

tcp_receive: pcb->rttest 0 rtseq 657 ackno 6538
tcp_receive: dequeued FIN.

In this situation, the socket layer will notify select() and the server app
will read the socket.  In this situation, the last bytes of the transfer are
delivered to the application, but not the EOF.  The server side never receives
a direct notification of the EOF.
In the sockets.c file its this function: lwip_recvfrom().  A FIN results in a
NULL msg sent to the netconn.
This results in this call returning ERR_CLSD:

 if (netconn_type(sock->conn) == NETCONN_TCP) {
        err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);

You see this in the log:
lwip_recvfrom: netconn_recv err=-12, netbuf=0

However, then below:
      if (err != ERR_OK) {
        if (off > 0) {

If off is greater than 0 then the leftover data is sent to the application and
returned. The knowledge of the error (in this case CLOSED) is lost, and
select() is never rewoken on the socket.  The workaround I have come up with
is if this happens, grab a lock and increment the rcvevent for the socket so
that select() will wake up the thread one more time and the application will
recall lwip_recvfrom() and this time it will grab the EOF:

      if (err != ERR_OK) {
        if (off > 0) {
          /* update receive window */
          netconn_recved(sock->conn, (u32_t)off);
          /* already received data, return that */
          sock_set_errno(sock, 0);
          // workaround begin
          sock->rcvevent++; /* signal one more receive event for NULL */
          // workaround end
          return off;

Again, this has to be a specific dropped packet - we ran across this because
of a MAC layer issue causing that particular packet to be dropped.  It appears
that if any other packet in the transmission is dropped (including the last
packet) than there are no issues.


Reply to this item at:


  Message sent via/by Savannah

reply via email to

[Prev in Thread] Current Thread [Next in Thread]