Hi All,
My application needs to 10 tcp server connections. All the examples that I have found are about tcp server use "echo" but in my application I need to send messages at any time, not only when it receive something from the client. So, I' ve based my code on the "tcp_echoserver" source code and it works for a while and then all the connection reset (wireshark sniffer). In the most of time, when the connection reset, it can't be reconnect and the pcb->state show an invalid value. Some times the pc get stuck in a "for" loop at pbuf_cat function. (And doesn't matter is I use 1, 4 or 10 connections, the result is the same).
void pbuf_cat(struct pbuf *h, struct pbuf *t)
{
struct pbuf *p;
LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
((h != NULL) && (t != NULL)), return;);
/* proceed to last pbuf of chain */
for (p = h; p->next != NULL; p = p->next) {
/* add total length of second chain to all totals of first chain */
p->tot_len += t->tot_len;
}
...
I'm trying to run my code over the enet_lwip example, with the TM4C129 launchpad, and the problem persist.
I belive that the problem maybe the adaptation from the tcp_echoserver I've made, so i really apreciate if someone can take a look and see what is wrong, indicate another way to do the server or another souce code to buid a tcp server.
I'm problably using the wrong the global tcp_pcb pointer, but I really have tryied in may ways and the connection never became stable.
---------------------
The entire code is attached. Below are some parts of my code that I have doubts:
I use this code below to send messages,at any time, from the application:
if( tcp_server_pcb[vSession]->state == ESTABLISHED )
{
indice = getPcbIndex( tcp_server_pcb[vSession]->local_port );
switch( indice )
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
if(( tcp_server_pcb[vSession]->state == ESTABLISHED )&&( len ))
{
if( tcp_write( tcp_server_pcb[vSession], buf , len, 0 ) == ERR_OK )
{
tcp_output( tcp_server_pcb[vSession] );
}
len = 0;
}
break;
}
}
and the changes that I've made:
//------------------------------------------------------------------------------------------------------------------------
//
//
//
// Parametros:
// Retorno:
//------------------------------------------------------------------------------------------------------------------------
static err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_struct *es;
uint8_t pcbIndex;
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 tcp_struct *)mem_malloc(sizeof(struct tcp_struct));
if (es != NULL)
{
es->state = ES_ACCEPTED;
es->pcb = newpcb;
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_recv_callback);
/* initialize lwip tcp_err callback function for newpcb */
tcp_err(newpcb, tcp_error_callback);
/* initialize lwip tcp_poll callback function for newpcb */
tcp_poll(newpcb, tcp_poll_callback, 1);
tcp_sent(newpcb, tcp_sent_callback);
ret_err = ERR_OK;
}
else
{
/* close tcp connection */
tcp_connection_close(newpcb, es);
/* return memory error */
ret_err = ERR_MEM;
}
// ADAPTED ( I guess that the "newpcb" should already be pointing to one of the "tcp_server_pcb" but "tcp_server_pcb->state" never changes ???)
pcbIndex = getPcbIndex( newpcb->local_port );
if( pcbIndex != 0xFF )
tcp_server_pcb[pcbIndex] = newpcb;
else
tcp_connection_close(newpcb, es);
return ret_err;
}
//------------------------------------------------------------------------------------------------------------------------
//
//
//
// Parametros:
// Retorno:
//------------------------------------------------------------------------------------------------------------------------
static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
struct tcp_struct *es;
err_t ret_err;
char *pc = NULL;
struct pbuf *ptr;
u16_t plen;
LWIP_ASSERT("arg != NULL",arg != NULL);
es = (struct tcp_struct *)arg;
/* if we receive an empty tcp frame from client => close connection */
if (p == NULL)
{
/* remote host closed connection */
es->state = ES_CLOSING;
if(es->p == NULL)
{
/* we're done sending, close connection */
tcp_connection_close(tpcb, es);
}
else
{
/* we're not done yet */
/* acknowledge received packet */
tcp_sent(tpcb, tcp_sent_callback);
/* send remaining data*/
tcp_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;
/* store reference to incoming pbuf (chain) */
es->p = p;
/* initialize LwIP tcp_sent callback function */
tcp_sent(tpcb, tcp_sent_callback);
//---------------------------------------------------------------------------
// app get the msg
if(es->p != NULL )
{
es->p = p;
pc = (char *)p->payload;
if( es->p->len > 0 )
{
app_getTcpPayloadMsg( tpcb->local_port, (uint8_t *)pc, p->len );
}
}
//--------------------------------------------
// adaptation from tcp_echo_server
ptr = es->p;
plen = ptr->len;
es->p = ptr->next;
if(es->p != NULL) pbuf_ref(es->p);
pbuf_free(ptr);
/* Update tcp window size to be advertized : should be called when received
data (with the amount plen) has been processed by the application layer */
tcp_recved(tpcb, plen);
ret_err = ERR_OK;
}
else if (es->state == ES_RECEIVED)
{
/* more data received from client and previous data has been already sent*/
if(es->p == NULL)
{
//---------------------------------------------------------------------------
// app get the msg
es->p = p;
pc = (char *)p->payload;
if( es->p->len > 0 )
{
app_getTcpPayloadMsg( tpcb->local_port, (uint8_t *)pc, p->len );
}
//--------------------------------------------
// adaptation from tcp_echo_server
ptr = es->p;
plen = ptr->len;
es->p = ptr->next;
if(es->p != NULL) pbuf_ref(es->p);
pbuf_free(ptr);
/* Update tcp window size to be advertized : should be called when received
data (with the amount plen) has been processed by the application layer */
tcp_recved(tpcb, plen);
}
else
{
struct pbuf *ptr;
/* chain pbufs to the end of what we recv'ed previously */
ptr = es->p;
pbuf_chain(ptr,p);
}
ret_err = ERR_OK;
}
/* data received when connection already closed */
else
{
/* Acknowledge data reception */
tcp_recved(tpcb, p->tot_len);
/* free pbuf and do nothing */
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err;
}
and the orignal tcp_echoserver:
http://www1.coocox.org/repo/d0b2d0af-9aca-4f53-aac1-a03176e84769/src/TCP_Server/tcp_server.c.htm
Thanks in advance.
