Hi i'm having some serious trouble developing a modbus server in lwip using
raw api, basically i got the server answering the requests, the problem is
that seemingly at random i get the following
mem_free: illegal memory: non-linked: double freemem_free: illegal
memory: non-linked: double free
The interesting part is that it seems to do so when closing a
connection due to an error if im not mistaken
i put a breakpoint where the message is produced and got the following
call stack
mem_free (void * rmem) Line: 717
pbuf_free (struct pbuf * p) Line: 780
tcp_seg_free (struct tcp_seg * seg) Line: 1631
tcp_segs_free (struct tcp_seg * seg) Line: 1616
tcp_pcb_purge (struct tcp_pcb * pcb, struct tcp_pcb * pcb@entry) Line: 2169
tcp_pcb_purge (struct tcp_pcb * pcb) Line: 2139
tcp_pcb_remove (struct tcp_pcb ** pcblist, struct tcp_pcb * pcb,
struct tcp_pcb * pcb@entry) Line: 2191
tcp_input (struct pbuf * p, struct pbuf * p@entry, struct netif * inp,
struct netif * inp@entry) Line: 448
ip4_input (struct pbuf * p, struct pbuf * p@entry, struct netif * inp,
struct netif * inp@entry) Line: 709
ethernet_input (struct pbuf * p, struct netif * netif) Line: 186
ethernetif_input (struct netif * netif) Line: 788
ethernet_task Line: 247
main Line: 929
so maybe this is related to lwipopts rather than the app?
the lwipopts file is the following
#define LWIP_NETIF_HOSTNAME 1#define LWIP_NETIF_API
0#define LWIP_NETIF_STATUS_CALLBACK 1#define LWIP_NETIF_LINK_CALLBACK
1
#define LWIP_SOCKET 0#define LWIP_NETCONN 0
#define SO_REUSE 1#define LWIP_IGMP 1
//#include <stmlib/rand.h>//#define LWIP_RAND rand_value
#define LWIP_STATS 1#define LWIP_STATS_DISPLAY 1
extern int printf(const char *format, ...);#define
LWIP_PLATFORM_DIAG(x) {printf x;}#define LWIP_DEBUG
#define LWIP_NOASSERT
#define LWIP_DBG_TYPES_ON (LWIP_DBG_STATE |
LWIP_DBG_ON)#define ETHARP_DEBUG
LWIP_DBG_OFF#define NETIF_DEBUG
LWIP_DBG_OFF#define DHCP_DEBUG
LWIP_DBG_OFF#define AUTOIP_DEBUG
LWIP_DBG_OFF#define IGMP_DEBUG
LWIP_DBG_OFF#define IP_DEBUG
LWIP_DBG_OFF#define PBUF_DEBUG
LWIP_DBG_LEVEL_SERIOUS#define MEM_DEBUG
LWIP_DBG_LEVEL_SERIOUS#define SIMPLE_DISCOVERY_DEBUG
LWIP_DBG_LEVEL_SERIOUS
#define TCP_TMR_INTERVAL 10
attached are the application files
if anyone can provide any lead i would be really grateful since i've
been stuck with this for a while and i don't think i know the innards
of lwip good enough to track this
modbusBal.h is the one that handles the queued packets
also i know this code isn't really clean and tidy, this is my first
lwip app and initially i just want to get it working more or less
reliably
best, diego
#ifndef MODBUSTCP_H_
#define MODBUSTCP_H_
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "../CONTROL_CONCURRENCIA/queue.h"
#include "../MEM_MGT/mempools.h"
#define MTCP_MAX_RETRIES 10
#define MTCP_QUEUE modbusTcpQueue
#define MTCP_QUEUE_BUF *mQueueBuffer[18]
#define MTCP_MEMP modbusTcpMemp
#ifndef MTCP_MAX_CONNS
#define MTCP_MAX_CONNS 5
#endif
extern queue_t MTCP_QUEUE;
extern void MTCP_QUEUE_BUF;
extern mempool_config MTCP_MEMP;
enum conn_status
{
MB_NONE = 0,
MB_CONNECTED,
MB_WAIT_TO_CLOSE,
MB_CLOSING
};
typedef struct
{
uint16_t transactionId;
uint16_t protocol;
uint16_t len;
uint8_t unitId;
} mbTcp_mbapHeader;
#define MBAP_PROTO_MB 0
typedef struct
{
uint8_t estado;
uint8_t retries;
struct tcp_pcb *pcb;
uint8_t *sendP;
uint8_t sendLen;
} mbTcp_status;
void modbusTcpStart(uint16_t port);
void modbusTcpStop(void);
err_t modbusTcpAccept(void *arg, struct tcp_pcb *pcb, err_t err);
err_t modbusTcpRecv(void *arg, struct tcp_pcb *mPcb, struct pbuf *p, err_t err);
void modbusTcpError(void *arg, err_t err);
err_t modbusTcpPoll(void *arg, struct tcp_pcb *mPcb);
void modbusTcpSend(struct tcp_pcb *mPcb, mbTcp_status *mbStatus);
err_t modbusTcpSent(void *arg, struct tcp_pcb *pcb, u16_t len);
void modbusTcpClose(struct tcp_pcb *pcb, mbTcp_status *mbStatus);
uint16_t swapBytes(uint8_t *ptr);
extern uint8_t mTcpCallGood(mbTcp_status *status, struct pbuf *p, mbTcp_mbapHeader hdr)
#endif*
* modbusTcp.c
*
* Created: 19/08/2019 14:05:11
* Author: diego
*/
#include "modbusTcp.h"
uint8_t actConns = 0;
uint16_t swapBytes(uint8_t *ptr)
{
uint16_t out = ((uint16_t) * (ptr + 1)) | ((uint16_t) * (ptr) << 8);
return out;
}
void modbusTcpStart(uint16_t port)
{
volatile err_t err;
struct tcp_pcb *pcb;
pcb = tcp_new();
//LWIP_ASSERT("falla al crear el pcb de modbus tcp", pcb != NULL);
if(pcb != NULL)
{
err = tcp_bind(pcb, IP_ADDR_ANY, port);
//tcp_setprio(pcb, MODBUS_TCP_PRIO);
//LWIP_ASSERT("Falla al iniciar modbus TCP (bind)", err == ERR_OK);
if(err == ERR_OK)
{
pcb = tcp_listen(pcb);
//LWIP_ASSERT("Falla al iniciar modbus TCP (listen)", err == ERR_OK);
tcp_accept(pcb, modbusTcpAccept);
return;
}
}
else
return;
}
err_t modbusTcpAccept(void *arg, struct tcp_pcb *mPcb, err_t err)
{
err_t ret_err;
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
if(actConns >= MTCP_MAX_CONNS)
{
return ERR_MEM;
}
else
{
actConns++;
}
tcp_setprio(mPcb, TCP_PRIO_MAX);
mbStatus = (mbTcp_status *)mem_malloc(sizeof(mbTcp_status));
if(mbStatus != NULL)
{
mbStatus->estado = MB_CONNECTED;
mbStatus->pcb = mPcb;
mbStatus->retries = 0;
mbStatus->sendP = NULL;
/* pass newly allocated es to our callbacks */
tcp_arg(mPcb, mbStatus);
tcp_recv(mPcb, modbusTcpRecv);
tcp_err(mPcb, modbusTcpError);
tcp_poll(mPcb, modbusTcpPoll, 0);
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err;
}
err_t modbusTcpRecv(void *arg, struct tcp_pcb *mPcb, struct pbuf *p, err_t err)
{
mbTcp_status *mbStatus;
volatile mbTcp_mbapHeader headerTmp;
mbStatus = (mbTcp_status *)arg;
uint8_t *payloadPtr = (uint8_t *) p->payload;
//tcp_output(mPcb);
if(p == NULL)
{
if(mbStatus->sendP == NULL)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
else
{
mbStatus->estado = MB_WAIT_TO_CLOSE;
//pbuf_free(p);
}
// esto es que queda algo para procesar en la cola
// la conexion se cerrara luego de que se procesen los que quedan
// simplemente se descarta el entrante
}
else
{
// queda algo para mandar
// asi que lo mandamos
tcp_sent(mPcb, modbusTcpSent);
//modbusTcpSend(mPcb, mbStatus);
}
}
else
if(err != ERR_OK)
{
mbStatus->sendP = NULL;
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return err;
}
else
{
switch(mbStatus->estado)
{
case MB_CONNECTED:
if(p->len == 0)
{
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
break;
}
headerTmp.transactionId = swapBytes(payloadPtr);
headerTmp.protocol = swapBytes(payloadPtr + 2);
headerTmp.len = swapBytes(payloadPtr + 4);
headerTmp.unitId = *(payloadPtr + 6);
if(mTcpCallGood(mbStatus, p, headerTmp) != 0)
{
if(p != NULL)
{
pbuf_free(p);
}
tcp_recved(mPcb, p->tot_len);
break;
}
// asumimos que los chequeos y demas fueron realizados por el stack
break;
case MB_WAIT_TO_CLOSE:
// notese que no ponemos mbStatus->p a NULL
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
break;
case MB_CLOSING:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
default:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
}
}
}
void modbusTcpError(void *arg, err_t err)
{
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(err);
mbStatus = (mbTcp_status *)arg;
tcp_arg(mbStatus->pcb, NULL);
tcp_sent(mbStatus->pcb, NULL);
tcp_recv(mbStatus->pcb, NULL);
tcp_err(mbStatus->pcb, NULL);
tcp_poll(mbStatus->pcb, NULL, 0);
tcp_close(mbStatus->pcb);
/*if(mbStatus != NULL)
{
mem_free(mbStatus);
}*/
}
void modbusTcpSend(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
err_t wr_err = ERR_OK;
while((wr_err == ERR_OK) &&
(mbStatus->sendP != NULL) &&
(mbStatus->sendLen <= tcp_sndbuf(mPcb))
)
{
wr_err = tcp_write(mPcb, mbStatus->sendP, mbStatus->sendLen, 1);
if(wr_err == ERR_OK)
{
mbStatus->sendLen = 0;
break;
}
else
if(wr_err == ERR_MEM)
{
// por ahora simplemente no mandamos nada
// idealmente seria defer to poll
}
}
return;
}
err_t modbusTcpPoll(void *arg, struct tcp_pcb *mPcb)
{
}
void modbusTcpClose(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
tcp_arg(mPcb, NULL);
tcp_sent(mPcb, NULL);
tcp_recv(mPcb, NULL);
tcp_err(mPcb, NULL);
tcp_poll(mPcb, NULL, 0);
if(mbStatus != NULL)
{
mem_free(mbStatus);
}
tcp_close(mPcb);
actConns--;
}
err_t modbusTcpSent(void *arg, struct tcp_pcb *mPcb, u16_t len)
{
mbTcp_status *mbStatus;
mbStatus = (mbTcp_status *)arg;
LWIP_UNUSED_ARG(len);
mbStatus->retries = 0;
if(mbStatus->estado == MB_WAIT_TO_CLOSE)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
}
// no quedan respuestas para mandar
// y ya no habia nada en la cola
if(mbStatus->estado == MB_CLOSING)
{
modbusTcpClose(mPcb, mbStatus);
}
return ERR_OK;
}*
* modbusTcp.c
*
* Created: 19/08/2019 14:05:11
* Author: diego
*/
#include "modbusTcp.h"
uint8_t actConns = 0;
uint16_t swapBytes(uint8_t *ptr)
{
uint16_t out = ((uint16_t) * (ptr + 1)) | ((uint16_t) * (ptr) << 8);
return out;
}
void modbusTcpStart(uint16_t port)
{
volatile err_t err;
struct tcp_pcb *pcb;
pcb = tcp_new();
//LWIP_ASSERT("falla al crear el pcb de modbus tcp", pcb != NULL);
if(pcb != NULL)
{
err = tcp_bind(pcb, IP_ADDR_ANY, port);
//tcp_setprio(pcb, MODBUS_TCP_PRIO);
//LWIP_ASSERT("Falla al iniciar modbus TCP (bind)", err == ERR_OK);
if(err == ERR_OK)
{
pcb = tcp_listen(pcb);
//LWIP_ASSERT("Falla al iniciar modbus TCP (listen)", err == ERR_OK);
tcp_accept(pcb, modbusTcpAccept);
return;
}
}
else
return;
}
err_t modbusTcpAccept(void *arg, struct tcp_pcb *mPcb, err_t err)
{
err_t ret_err;
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
if(actConns >= MTCP_MAX_CONNS)
{
return ERR_MEM;
}
else
{
actConns++;
}
tcp_setprio(mPcb, TCP_PRIO_MAX);
mbStatus = (mbTcp_status *)mem_malloc(sizeof(mbTcp_status));
if(mbStatus != NULL)
{
mbStatus->estado = MB_CONNECTED;
mbStatus->pcb = mPcb;
mbStatus->retries = 0;
mbStatus->sendP = NULL;
/* pass newly allocated es to our callbacks */
tcp_arg(mPcb, mbStatus);
tcp_recv(mPcb, modbusTcpRecv);
tcp_err(mPcb, modbusTcpError);
tcp_poll(mPcb, modbusTcpPoll, 0);
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err;
}
err_t modbusTcpRecv(void *arg, struct tcp_pcb *mPcb, struct pbuf *p, err_t err)
{
mbTcp_status *mbStatus;
volatile mbTcp_mbapHeader headerTmp;
mbStatus = (mbTcp_status *)arg;
uint8_t *payloadPtr = (uint8_t *) p->payload;
//tcp_output(mPcb);
if(p == NULL)
{
if(mbStatus->sendP == NULL)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
else
{
mbStatus->estado = MB_WAIT_TO_CLOSE;
//pbuf_free(p);
}
// esto es que queda algo para procesar en la cola
// la conexion se cerrara luego de que se procesen los que quedan
// simplemente se descarta el entrante
}
else
{
// queda algo para mandar
// asi que lo mandamos
tcp_sent(mPcb, modbusTcpSent);
//modbusTcpSend(mPcb, mbStatus);
}
}
else
if(err != ERR_OK)
{
mbStatus->sendP = NULL;
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return err;
}
else
{
switch(mbStatus->estado)
{
case MB_CONNECTED:
if(p->len == 0)
{
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
break;
}
headerTmp.transactionId = swapBytes(payloadPtr);
headerTmp.protocol = swapBytes(payloadPtr + 2);
headerTmp.len = swapBytes(payloadPtr + 4);
headerTmp.unitId = *(payloadPtr + 6);
if(mTcpCallGood(mbStatus, p, headerTmp) != 0)
{
if(p != NULL)
{
pbuf_free(p);
}
tcp_recved(mPcb, p->tot_len);
break;
}
// asumimos que los chequeos y demas fueron realizados por el stack
break;
case MB_WAIT_TO_CLOSE:
// notese que no ponemos mbStatus->p a NULL
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
break;
case MB_CLOSING:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
default:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
}
}
}
void modbusTcpError(void *arg, err_t err)
{
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(err);
mbStatus = (mbTcp_status *)arg;
tcp_arg(mbStatus->pcb, NULL);
tcp_sent(mbStatus->pcb, NULL);
tcp_recv(mbStatus->pcb, NULL);
tcp_err(mbStatus->pcb, NULL);
tcp_poll(mbStatus->pcb, NULL, 0);
tcp_close(mbStatus->pcb);
/*if(mbStatus != NULL)
{
mem_free(mbStatus);
}*/
}
void modbusTcpSend(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
err_t wr_err = ERR_OK;
while((wr_err == ERR_OK) &&
(mbStatus->sendP != NULL) &&
(mbStatus->sendLen <= tcp_sndbuf(mPcb))
)
{
wr_err = tcp_write(mPcb, mbStatus->sendP, mbStatus->sendLen, 1);
if(wr_err == ERR_OK)
{
mbStatus->sendLen = 0;
break;
}
else
if(wr_err == ERR_MEM)
{
// por ahora simplemente no mandamos nada
// idealmente seria defer to poll
}
}
return;
}
err_t modbusTcpPoll(void *arg, struct tcp_pcb *mPcb)
{
}
void modbusTcpClose(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
tcp_arg(mPcb, NULL);
tcp_sent(mPcb, NULL);
tcp_recv(mPcb, NULL);
tcp_err(mPcb, NULL);
tcp_poll(mPcb, NULL, 0);
if(mbStatus != NULL)
{
mem_free(mbStatus);
}
tcp_close(mPcb);
actConns--;
}
err_t modbusTcpSent(void *arg, struct tcp_pcb *mPcb, u16_t len)
{
mbTcp_status *mbStatus;
mbStatus = (mbTcp_status *)arg;
LWIP_UNUSED_ARG(len);
mbStatus->retries = 0;
if(mbStatus->estado == MB_WAIT_TO_CLOSE)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
}
// no quedan respuestas para mandar
// y ya no habia nada en la cola
if(mbStatus->estado == MB_CLOSING)
{
modbusTcpClose(mPcb, mbStatus);
}
return ERR_OK;
}_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users