FreeRTOS_accept with STM32H757 - LAN8274 TCP IP Server

Hello everyone,

I have an issue with FreeRTOS_accept with STM32H757 and LAN8274 PHY.
I’m using the network driver provided with FreeRTOS-PLUS-TCP v4.1.0

It successfully accepts one incoming connection from a client, then the client closes the connection. At the second connection attempt, FreeRTOS_accept does not return a socket. It remains blocked.

I assured that the task is still running by adding a timeout to FreeRTOS_accept and check that the accept call periodically returns. But it still does not return when there is a new incoming connection.

I can see incoming data when the second connection happens in

        case eNetworkRxEvent:

but prvAcceptWaitClient remains suspended.

I also want to mention that this specific code works in another product with the same MCU where we use a different PHY (in that case it a switch KSZ9563)

Any idea what could go wrong or how can I further debug the issue?

Thank you

Here is the code:

      struct freertos_sockaddr client;
      struct freertos_sockaddr bind_address;
      Socket_t listening_socket;

      socklen_t client_size = sizeof(client);
      static const TickType_t receive_timeout = portMAX_DELAY;

      WinProperties_t xWinProps;

      /* Fill in the buffer and window sizes that will be used by the socket. */
      xWinProps.lTxBufSize = 4 * ipconfigTCP_TX_BUFFER_LENGTH;
      xWinProps.lTxWinSize = 4 * 2;
      xWinProps.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH;
      xWinProps.lRxWinSize = 2;

      /* Attempt to open the socket. */
      listening_socket =
          FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
      configASSERT(listening_socket != FREERTOS_INVALID_SOCKET);

      /* Set a time out so accept() will just wait for a connection. */
      FreeRTOS_setsockopt(
          listening_socket, 0, FREERTOS_SO_RCVTIMEO, &receive_timeout, sizeof(receive_timeout));

      /* Set the window and buffer sizes. */
      FreeRTOS_setsockopt(
          listening_socket, 0, FREERTOS_SO_WIN_PROPERTIES, (void*)&xWinProps, sizeof(xWinProps));

      bind_address.sin_port = FreeRTOS_htons(server->port);
      FreeRTOS_bind(listening_socket, &bind_address, sizeof(bind_address));
      FreeRTOS_listen(listening_socket, max_connections);

      for (;;) {
        server->connected_socket = FreeRTOS_accept(listening_socket, &client, &client_size);
        configASSERT(server->connected_socket != FREERTOS_INVALID_SOCKET);
        xTaskCreate(ConnectionTask,
                    "ConnectionTask",
                    2048,
                    (void*)server,
                    LumTasksPriorities::kNormal,
                    NULL);
      }

what is the code for your connection task? Do you have a wireshark trace?

Connection Task:

void Server::ConnectionTask(void *parameters) {
  static const TickType_t rx_timeout = pdMS_TO_TICKS(1);
  static const TickType_t tx_timeout = pdMS_TO_TICKS(5000);
  static const TickType_t tcp_echo_shutdown_delay = pdMS_TO_TICKS(5000);

  TickType_t time_on_shutdown;
  uint8_t rx_buffer[ipconfigTCP_MSS];

  Server *server = (Server *)parameters;

  FreeRTOS_setsockopt(server->connected_socket, 0, FREERTOS_SO_RCVTIMEO,
                      &rx_timeout, sizeof(rx_timeout));
  FreeRTOS_setsockopt(server->connected_socket, 0, FREERTOS_SO_SNDTIMEO,
                      &tx_timeout, sizeof(tx_timeout));

  for (;;) {
    memset(rx_buffer, 0x00, ipconfigTCP_MSS);
    BaseType_t bytes_received = FreeRTOS_recv(server->connected_socket,
                                              rx_buffer, sizeof(rx_buffer), 0);
    if (bytes_received > 0) {
      // ToDo(ugo): Move process data to dedicated function
      // Process data
      for (uint16_t index = 0; index < bytes_received; index++) {
        if (server->in_pkt.Parse(rx_buffer[index])) {
          PktRouter::Route(*server->routing_table_, server->in_pkt,
                           &server->out_pkt);
          FreeRTOS_send(server->connected_socket, server->out_pkt.GetBytes(),
                        server->out_pkt.GetSizeInUse(), 0);
        }
      }
    } else if (bytes_received == 0) {
      // Socket timeout, used to push data to connected client
    } else {
      // Socket closed by client or socket error
      break;
    }
  }
  FreeRTOS_shutdown(server->connected_socket, FREERTOS_SHUT_RDWR);

  // Wait for the shutdown to take effect, indicated by FreeRTOS_recv()
  // returning an error.
  time_on_shutdown = xTaskGetTickCount();
  do {
    if (FreeRTOS_recv(server->connected_socket, rx_buffer, ipconfigTCP_MSS, 0) <
        0) {
      break;
    }
  } while ((xTaskGetTickCount() - time_on_shutdown) < tcp_echo_shutdown_delay);

  FreeRTOS_closesocket(server->connected_socket);

  // Delete the task
  vTaskDelete(NULL);
}

rtos-accept-fails.zip (614.9 KB)

If you re-use the connected_socket member of your server socket, you have two tasks partying on the same socket concurrently. That calls for trouble.

Thank you @RAc for the reply.
I agree with you that this design does not support multiple connections. max_connections = 1.

With max_connections = 1 FreeRTOS_accept will not accept another connection until the first one is closed. So I should be able to reuse connected_socket for the second incoming connection.

In any case, FreeRTOS_accept does not return ever again after the first client disconnection. So reusing connected_socket is not the issue.

No, this is not true. Your accept loop will overwrite the connected_socket member as soon as a second client will attempt to connect to your end point. At that point, your first task may still be using that member.

Try replacing the xTaskCreate in your listener task with a direct call to the task function. My suspicion is that you will then see orderly communication.

@RAc I tried and it is as I say. With

FreeRTOS_listen(listening_socket, 1);

FreeRTOS_accept does not return a second time until the first socket is closed. Anyway it is good you pointed out so I’ll change it when we will support multiple connections.

The problem was with xApplicationGetRandomNumber.
I didn’t initialized properly the HW so the function would not return a random number, so the second time the client would try to connect, ulInitialSequenceNumber would be 0.

Thank you for reporting back!