cancel
Showing results for 
Search instead for 
Did you mean: 

How to send data LwIP tcp server to client ?

oziesin
Associate III

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.

1 ACCEPTED SOLUTION

Accepted Solutions
oziesin
Associate III

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.

View solution in original post

3 REPLIES 3

"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

oziesin
Associate III

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.

Hi Oziesin, could you send me a full source code? I've met the same issue.