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.