ctcpstm32ethernetlwip

TCP LwIP server does not respond to [FIN,ACK] from the TCP client?


so if you look into my post history you will know that I have been trying a project in TCP using LwIP. I was unable to capture data in the server side, but now I have resolved that issue. But now I have a new one.

I connect to the TCP server(STM32-nucleo-144) and the wireshark shows the three-way-handshake happening between the server and the client, then I send messages to the server and the server responds as per the programming, now I terminate the connection on the client side, the client sends a packet with [FIN,ACK] flags set, but the server never responds back with a [FIN,ACK]. I use an App for TCP transmission called hercules, when I press 'disconnect' it displays the message connection closed when it never really happened as it can be seen from wireshark.

I also used another app to check, this app sends TCP packets continuously at predefined intervals, it creates a connection, sends packets, accepts a response then closes the connection, and after the interval it repeats this process again. When I started this app, the first connection was created, data was sent and received by the client, the [FIN,ACK] flags were sent by the client but no response from server from there on.

I did a ping test, it seems the server becomes unreachable as soon as the disconnect starts.

Here is my code:-

 /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_LWIP_Init();
  /* USER CODE BEGIN 2 */


  IP_ADDR4(&myIPADDR,192,168,33,2);
  IP_ADDR4(&destip,192,168,33,101);

  tcp_pcb = tcp_new();

  err_t err = tcp_bind(tcp_pcb, &myIPADDR, 4100);

  if(err == ERR_OK)
    {
      tcp_pcb = tcp_listen_with_backlog(tcp_pcb, 2);

      tcp_accept(tcp_pcb, tcp_echoserver_accept);
    }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      ethernetif_input(&gnetif);
      sys_check_timeouts();

  }
  /* USER CODE END 3 */
}
err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{


    tcp_arg(tcp_newpcb, tcp_newpcb);
    tcp_recv(newpcb, recv_callback);
    return ERR_OK;

}

err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{

    sprintf(data, "this is the message: '%s'", p->payload);

    tcp_recved(tpcb, p->len);
    tcp_write(tpcb, data,p->len+23, 0x02);

    pbuf_free(p);

    err = ERR_OK;
    return err;
}

Here is what is shown is wireshark after i press the disconnect butotn in hercules

13366   6286.571000 192.168.33.101  192.168.33.2    TCP 54  52649 → 4100 [FIN, ACK] Seq=12 Ack=35 Win=65358 Len=0

13367   6286.883778 192.168.33.101  192.168.33.2    TCP 54  [TCP Retransmission] 52649 → 4100 [FIN, ACK] Seq=12 Ack=35 Win=65358 Len=0

13369   6287.498291 192.168.33.101  192.168.33.2    TCP 54  [TCP Retransmission] 52649 → 4100 [FIN, ACK] Seq=12 Ack=35 Win=65358 Len=0

13371   6288.709492 192.168.33.101  192.168.33.2    TCP 54  [TCP Retransmission] 52649 → 4100 [FIN, ACK] Seq=12 Ack=35 Win=65358 Len=0

13374   6291.112720 192.168.33.101  192.168.33.2    TCP 54  [TCP Retransmission] 52649 → 4100 [FIN, ACK] Seq=12 Ack=35 Win=65358 Len=0

Solution

  • In your receive callback, you have to check if the pbuf pointer p is NULL in which case, the connection was closed at the other end and you need to call tcp_close. The reason why the server becomes unreachable is because you are dereferencing a NULL pointer, which would trigger a hard fault.