2022-06-29 12:36 AM
I have basic application of tcp_server.
void tcp_echoserver_init( uint16_t port)
{
tcp_echoserver_pcb = tcp_new();
if ( tcp_echoserver_pcb != NULL)
{
err_t err;
/* bind echo_pcb to port (ECHO protocol) */
err = tcp_bind( tcp_echoserver_pcb, IP_ADDR_ANY, port);
if (err == ERR_OK)
{
/* start tcp listening for echo_pcb */
tcp_echoserver_pcb = tcp_listen( tcp_echoserver_pcb );
/* initialize LwIP tcp_accept callback function */
tcp_accept( tcp_echoserver_pcb , tcp_echoserver_accept);
}
else
{
/* deallocate the pcb */
memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb );
}
}
}
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct echoserver *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
/* set priority for the newly accepted tcp connection newpcb */
tcp_setprio(newpcb, TCP_PRIO_MIN);
/* allocate structure es to maintain tcp connection informations */
es = (struct echoserver *)mem_malloc(sizeof(struct echoserver));
if (es != NULL)
{
es->state = ES_ACCEPTED;
es->pcb = newpcb; //newpcb;
es->retries = 0;
es->p = NULL;
/* pass newly allocated es structure as argument to newpcb */
tcp_arg(newpcb, es);
/* initialize lwip tcp_recv callback function for newpcb */
tcp_recv(newpcb, tcp_echoserver_recv);
/* initialize lwip tcp_err callback function for newpcb */
tcp_err(newpcb, tcp_echoserver_error);
/* initialize lwip tcp_poll callback function for newpcb */
tcp_poll(newpcb, tcp_echoserver_poll, 0);
ret_err = ERR_OK;
}
else
{
/* close tcp connection */
tcp_echoserver_connection_close(newpcb, es);
/* return memory error */
ret_err = ERR_MEM;
}
return ret_err;
}
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
struct echoserver *es;
err_t ret_err;
LWIP_ASSERT("arg != NULL",arg != NULL);
es = (struct echoserver *)arg;
/* if we receive an empty tcp frame from client => close connection */
if (p == NULL)
{
/* remote host closed connection */
es->state = ES_CLOSING_SERVER;
if(es->p == NULL)
{
/* we're done sending, close connection */
tcp_echoserver_connection_close(tpcb, es);
}
else
{
/* we're not done yet */
/* acknowledge received packet */
tcp_sent(tpcb, tcp_echoserver_sent);
/* send remaining data*/
tcp_echoserver_send(tpcb, es);
}
ret_err = ERR_OK;
}
/* else : a non empty frame was received from client but for some reason err != ERR_OK */
else if(err != ERR_OK)
{
/* free received pbuf*/
if (p != NULL)
{
es->p = NULL;
pbuf_free(p);
}
ret_err = err;
}
else if(es->state == ES_ACCEPTED)
{
/* first data chunk in p->payload */
es->state = ES_RECEIVED_SERVER;
/* store reference to incoming pbuf (chain) */
es->p = p;
/* initialize LwIP tcp_sent callback function */
tcp_sent(tpcb, tcp_echoserver_sent);
/* send back the received data (echo) */
tcp_echoserver_send(tpcb, es);
ret_err = ERR_OK;
}
else if (es->state == ES_RECEIVED_SERVER)
{
/* more data received from client and previous data has been already sent*/
if(es->p == NULL)
{
es->p = p;
/* send back received data */
tcp_echoserver_send(tpcb, es);
}
else
{
struct pbuf *ptr;
ptr = es->p;
pbuf_chain(ptr,p);
}
ret_err = ERR_OK;
}
else if(es->state == ES_CLOSING)
{
/* odd case, remote side closing twice, trash data */
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
else
{
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err;
}
static void tcp_echoserver_error(void *arg, err_t err)
{
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(err);
es = (struct tcp_echoserver_struct *)arg;
if (es != NULL)
{
/* free es structure */
mem_free(es);
}
}
static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct echoserver *es;
es = (struct echoserver *)arg;
if (es != NULL)
{
if (es->p != NULL)
{
tcp_sent(tpcb, tcp_echoserver_sent);
/* there is a remaining pbuf (chain) , try to send data */
tcp_echoserver_send(tpcb, es);
}
else
{
/* no remaining pbuf (chain) */
if(es->state == ES_CLOSING_SERVER)
{
/* close tcp connection */
tcp_echoserver_connection_close(tpcb, es);
}
}
ret_err = ERR_OK;
}
else
{
/* nothing to be done */
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}
static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct echoserver *es;
LWIP_UNUSED_ARG(len);
es = (struct echoserver *)arg;
es->retries = 0;
if(es->p != NULL)
{
/* still got pbufs to send */
tcp_sent(tpcb, tcp_echoserver_sent);
tcp_echoserver_send(tpcb, es);
}
else
{
/* if no more data to send and client closed connection*/
if(es->state == ES_CLOSING_SERVER)
tcp_echoserver_connection_close(tpcb, es);
}
return ERR_OK;
}
static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct echoserver *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
while ( (wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= tcp_sndbuf(tpcb)))
{
/* get pointer on pbuf from es structure */
ptr = es->p;
/* enqueue data for transmission */
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK)
{
u16_t plen;
u8_t freed;
plen = ptr->len;
/* continue with next pbuf in chain (if any) */
es->p = ptr->next;
if(es->p != NULL)
{
/* increment reference count for es->p */
pbuf_ref(es->p);
}
/* chop first pbuf from chain */
do
{
/* try hard to free pbuf */
freed = pbuf_free(ptr);
}
while(freed == 0);
/* we can read more data now */
tcp_recved(tpcb, plen);
}
else if(wr_err == ERR_MEM)
{
/* we are low on memory, try later / harder, defer to poll */
es->p = ptr;
}
else
{
/* other problem ?? */
}
}
}
static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct echoserver *es)
{
/* remove all callbacks */
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
/* delete es structure */
if (es != NULL)
{
mem_free(es);
}
/* close tcp connection */
tcp_close(tpcb);
}
I use this functions, it can send whenever data received from client and echo it but if i call tcp_echoserver_send( newpcb, &es ); anywhere of code, cannot send.
I encountered assertion like below,
Assertion "tcp_write: invalid pcb" failed at line 414 in C:/Works/Projects/STM32Cube_FW_F2_V1.9.0/Middlewares/Third_Party/LwIP/src/core/tcp_out.c
Any help would be appriciated, thanks.
Solved! Go to Solution.
2022-07-01 12:39 AM
I found the solution. The problem was struct echoserver *es declared as a local variable in accept function. I use global variable and it works properly.
2022-06-29 01:13 AM
"Assertion 'tcp_write: invalid pcb' failed at line 414 in"
So set a breakpoint at that point, and see what's wrong with the pcb
2022-07-01 12:39 AM
I found the solution. The problem was struct echoserver *es declared as a local variable in accept function. I use global variable and it works properly.
2024-10-11 09:53 AM
Hi Oziesin, could you send me a full source code? I've met the same issue.
2025-02-06 10:20 AM
I have spent a lot of time building a TCP server based application which initially used this example. My strong suggestion is to check the stack sizes of the threads lwip uses. MX Cube may not be making them large enough and this can manifest as hard faults later on when you start sending large amount of data or running the server for a long time. I increased the size of the "ethernetif_input" thread to 1600 in ethernetif.c and the "ethernet_link_thread" thread to 1600 in lwip.c
I also stopped using the lower level raw tcp calls in the example and started using the nettcon interface which was more reliable at least in my testing. An example nettcon TCP server is pretty easy to find with some googling.