UltimaSerial Fixing a glitch in AVR32's lwIP adoption that causes erratic behaviors in unblocking option of lwip_recvfrom
 

Data logger
UltimaSerial

 

Windaq add-ons
Windaq Add-ons

 

Spectrogram
UltimaWaterfall

 

Ultimaserial XChart
XChart

 

FFT1024
FFT1024

 

Ultimaserial Classroom
Lessons

lwIP (lightweightIP)  is a popular free TCP/IP stack for many embedded processors, including Atmel's AVR32 framework

The version of lwIP in my AVR32 Framework is 1.3.0

When I open a TCP connection, I don't like to use blocking method to call lwip_recv, for it will not return until it receives something from the socket, so I always use unblocking option.

Everything seems fine  until I try to send a lot of small packets to it in a short burst. You will not lose any packets, but the internal counter for incoming packets will be messed up. When this happens, the next unblocking calls to lwip_recvfrom will lose sync and turn into a blocking one!

With the help of lwIP's team, the following patch can be applied to lwIP to fix the bug. 

Due to the difference in the lwIP's version controls, You will need to apply the follow patch manually. 

Open the affected files, use the line number as reference, which may not be in the exact spot. Remove the text indicated with - and add the text with leading + (remove + before adding the text).

Open YourProject->src->SOFTWARE_FRAMEWORK->SERVICES->lwip-1.3.0->src->api->api_msg.c

@@ -108,11 +108,13 @@
buf->addr = &(((struct ip_hdr*)(q->payload))->src);
buf->port = pcb->protocol;

- SYS_ARCH_INC(conn->recv_avail, q->tot_len);
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);

if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
netbuf_delete(buf);
+ return 0;
+ } else {
+ SYS_ARCH_INC(conn->recv_avail, q->tot_len);
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);

}
}
}

@@ -166,12 +168,13 @@
buf->port = port;
}

- SYS_ARCH_INC(conn->recv_avail, p->tot_len);
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);

if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
netbuf_delete(buf);
return;
+ } else {
+ SYS_ARCH_INC(conn->recv_avail, p->tot_len);
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);

}
}
#endif /* LWIP_UDP */

@@ -206,10 +209,12 @@
} else {
len = 0;
}
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);

+
if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
return ERR_MEM;
+ } else {
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);

}

return ERR_OK;


@@ -365,8 +370,6 @@
newconn->pcb.tcp = newpcb;
setup_tcp(newconn);
newconn->err = err;
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);


if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
/* When returning != ERR_OK, the connection is aborted in tcp_process(),


@@ -374,7 +377,11 @@
newconn->pcb.tcp = NULL;
netconn_free(newconn);
return ERR_MEM;
+ } else {
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

}
+
return ERR_OK;
}
#endif /* LWIP_TCP */

Open YourProject->src->SOFTWARE_FRAMEWORK->SERVICES->lwip-1.3.0->src->api->sockets.c

@@ -66,7 +66,7 @@
u16_t lastoffset;
/** number of times data was received, set by event_callback(),
tested by the receive and select functions */
- u16_t rcvevent;
+ s16_t rcvevent;
/** number of times data was received, set by event_callback(),
tested by select */
u16_t sendevent;


@@ -260,7 +260,7 @@
if (!sock)
return -1;

- if ((sock->flags & O_NONBLOCK) && !sock->rcvevent) {
+ if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
return -1;


@@ -494,7 +494,8 @@
buf = sock->lastdata;
} else {
/* If this is non-blocking call, then check first */
- if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) {
+ if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && 
+ (sock->rcvevent <= 0)) {

if (off > 0) {
/* already received data, return that */
sock_set_errno(sock, 0);


@@ -545,7 +546,10 @@
if (netconn_type(sock->conn) == NETCONN_TCP) {
LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
len -= copylen;
- if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent || ((flags & MSG_PEEK)!=0)) {
+ if ( (len <= 0) || 
+ (buf->p->flags & PBUF_FLAG_PUSH) || 
+ (sock->rcvevent <= 0) || 
+ ((flags & MSG_PEEK)!=0)) {

done = 1;
}
} else {


@@ -852,7 +856,7 @@
if (FD_ISSET(i, readset)) {
/* See if netconn of this socket is ready for read */
p_sock = get_socket(i);
- if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) {
+ if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) {
FD_SET(i, &lreadset);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
nready++;


@@ -1100,7 +1104,7 @@
if (scb->sem_signalled == 0) {
/* Test this select call for our socket */
if (scb->readset && FD_ISSET(s, scb->readset))
- if (sock->rcvevent)
+ if (sock->rcvevent > 0)
break;
if (scb->writeset && FD_ISSET(s, scb->writeset))
if (sock->sendevent)

Open YourProject->src->SOFTWARE_FRAMEWORK->SERVICES->lwip-1.3.0->src-> include/lwip/api.h


@@ -137,7 +137,7 @@
/** maximum amount of bytes queued in recvmbox */
int recv_bufsize;
#endif /* LWIP_SO_RCVBUF */
- u16_t recv_avail;
+ s16_t recv_avail;
#if LWIP_TCP
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores the message. */

Upgrade to the latest lwIP and you won't need to do the above!

 Click here for more lwIP examples

 

 

 

 

 Last update: 02/29/12