lwIP Wiki
Advertisement

We are using LWIP 1.3.2(as ported by TexasInstruments), IAR compiler targeting a stellaris MCU. The TI implementation uses a timer tick interrupt 100 times/sec to service the LWIP stack. No RTOS involved. Our application code also runs on this same timer tick interrupt so no concurrency issues in play.

We implemented a webservice http client over tcp. Periodically(about 1-2 times per day), we miss ACKs in the application layer. Plain and simple, our tcp_sent callback does not get called. We have timers that expire if the ack is not seen. I have captured the WireShark trace and the ack is being transmitted. For some reason the lwip stack does not inform the application layer. I don’t know if the LWIP stack sees the ack or not.

The odd thing is that under normal load conditions the code works and transmits 2-3 large HTTP posts/second. This means that within a 12 hour period it works 2*60*60 *12= 86,400 times without error.

I have adjusted the lwipopts.h settings over and over and nothing seems to affect the problem.

I have scanned the 1.4.1 changelog and do not see any defects that specifically address this problem, Further complicating the issue is that TI has not ported 1.4.1. If they had I would have tried it to see if it solves the problem. I am not sure how much effort it will be to do the port myself. I am willing to do it if there is a specific defect that address my issue.



Here is how the callbacks are being set up:


 if(s_Pcb == NULL)
 {
   s_Pcb = tcp_new();
   err_t bindResult = tcp_bind(s_Pcb, IP_ADDR_ANY, PortNumber);
   UpdateCounters(&g_Diagnostics.BindCounters, bindResult);
   if(bindResult != ERR_OK)
   {
     ClosePcb();
     // try again next time
     return;
   }
   // Setup the TCP callback functions
   tcp_err(s_Pcb, OnError);
   tcp_sent(s_Pcb, OnSent);
   tcp_recv(s_Pcb, OnReceive);
   return;
 }

How we send a chunk of the overall HTTP message:

//***************************************************************************** // Send next chunk of the message. //***************************************************************************** void ContinueTransmittingHttpPostMessage() {

 err_t result;
 g_BytesAvailable = tcp_sndbuf(s_Pcb);
 g_BytesToSend = Message.StopIndex - Message.TransmitIndex;
 if(g_BytesToSend > 0)
 {
   if(g_BytesToSend > TCP_WND)
   {
     g_BytesToSend = TCP_WND;
   }
   if(g_BytesAvailable >= g_BytesToSend)
   {
     result = tcp_write(s_Pcb, &Message.Body[Message.TransmitIndex], g_BytesToSend, 0);
     UpdateCounters(&g_Diagnostics.WriteCounters, result);
     if(result == ERR_OK)
     {
       g_Diagnostics.ulTotalBytesWritten += g_BytesToSend;
       Message.TransmitIndex += g_BytesToSend;
       Message.State = Sending;
       SetTimeout(&Message.StateTimer, 2 Sec);
     }
     else
     {
       StopTransmittingHttpPostMessage();
     }
   }
   else
   {
     g_Diagnostics.ulSendBufferFullErrors++;
   }
 }

}

The tcp_sent callback that doesn’t get call (sometimes).

//***************************************************************************** // Our TCP sent callback. // Look at tcp_sent for for information. //***************************************************************************** static err_t OnSent(void *arg, struct tcp_pcb *pcb, u16_t numBytesAcknowledged) {

 // Service the watchdog timer
 ServiceWatchdogTimer();
 // We only get called if the web service received > 0 bytes
 g_Diagnostics.ulOnSentCallbacks++;
 g_Diagnostics.ulTotalBytesAcknowledged +=numBytesAcknowledged;
 if(Message.State == Sending)
 {
   Message.BytesAcked += numBytesAcknowledged;
   if(Message.TransmitIndex >= Message.StopIndex)
   {
     if(Message.BytesAcked >= Message.StopIndex)
     {
       Message.State = WaitingForOk;
       SetTimeout(&Message.StateTimer, 2 Sec);
     }
   }
   else
   {
     ContinueTransmittingHttpPostMessage();
   }
 }
 return ERR_OK;

}

Advertisement