FreeRTOS + TCP - Client Server communication Fail

Hi there, I’m trying to enstablish a Client/Server communication. I have 2 AEK-COM-10BASET boards connected by ethernet.

These boards embeds 2 ethernet PHY transceivers, which I will name “eth0” and “eth1”:
The network_cfg.h for both boards defines these IPs:
#define SPC5_ETH0_IP_ADDR “192.168.1.1”
#define SPC5_ETH1_IP_ADDR “192.168.1.2”

This is my server main task:

void remote_connect_and_listenTask( void *pvParam ){
const BaseType_t xBacklog = 10; //massimo numero di connessioni 10
BaseType_t ret_bind, ret_listen;
Socket_t xListeningSocket, xConnectedSocket;
struct freertos_sockaddr xBindAddress;
struct freertos_sockaddr connected_client;
socklen_t connected_client_size = sizeof(connected_client);
static const TickType_t acpt_tout =   pdMS_TO_TICKS(1000); 
const char *pcInterfaceName = "eth0"; //test8650 // eth0=8670
uint8_t received_eth_msg[6];
char* cBuffer;
BaseType_t xReceivedBytes, result;
xListeningSocket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
if (xListeningSocket != FREERTOS_INVALID_SOCKET)
{
	FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_BINDTODEVICE, pcInterfaceName, strlen(pcInterfaceName));
	FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_SNDTIMEO, &acpt_tout, sizeof(acpt_tout));
	FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &acpt_tout, sizeof(acpt_tout));

	xBindAddress.sin_port = FreeRTOS_htons( ETH_PORT );
	xBindAddress.sin_addr = FreeRTOS_inet_addr(SPC5_ETH0_IP_ADDR);
	//connected_client.sin_port = FreeRTOS_htons( ETH_PORT );
	//connected_client.sin_addr = FreeRTOS_inet_addr("192.168.1.2");
	ret_bind = FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); //bind to 5555
    /* Ascolto delle connessioni */
	ret_listen = FreeRTOS_listen( xListeningSocket, xBacklog );
	//configASSERT(ret == 0);
    for( ;; )
    {/* Accetta una connessione */
        xConnectedSocket = FreeRTOS_accept( xListeningSocket, &connected_client, &connected_client_size );
        if (xConnectedSocket != FREERTOS_INVALID_SOCKET)
        {/* Ricezione dei dati */
            xReceivedBytes = FreeRTOS_recv(xConnectedSocket, &received_eth_msg, 6, 0 );
            if( xReceivedBytes > 0 )
            {  	cBuffer = &received_eth_msg;
            	//px_rcv_eth_msg = &received_eth_msg;
       			//result = xQueueSend(schedulingMessageQueue, (void*)(&px_rcv_eth_msg), 0);
       			xTaskNotifyGive(schedulerTaskHandler);
            }
        }
    }
}
}

and This is my CLIENT task, installed in the other board:

void init_socket_comm_Task ( void *pvParam ){
(void)pvParam;
static const TickType_t acpt_tout =  pdMS_TO_TICKS(5000); // Timeout di 20 secondi
BaseType_t ret_socket, ret_connect, ret_addr;
Socket_t xClientSocket;
const char *pcInterfaceName = "eth1"; //8650
struct freertos_sockaddr xServerAddress, xClientAddress;
uint8_t cBuffer[6] = {1,2,3,4,5,9};
BaseType_t xSentBytes;
xClientSocket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
// FreeRTOS_setsockopt(xClientSocket, 0, FREERTOS_SO_BINDTODEVICE, pcInterfaceName, strlen(pcInterfaceName));
FreeRTOS_setsockopt(xClientSocket, 0, FREERTOS_SO_SNDTIMEO, &acpt_tout, sizeof(acpt_tout));
FreeRTOS_setsockopt(xClientSocket, 0, FREERTOS_SO_RCVTIMEO, &acpt_tout, sizeof(acpt_tout));
xServerAddress.sin_len = sizeof xServerAddress;
xServerAddress.sin_family = FREERTOS_AF_INET;
xServerAddress.sin_port = FreeRTOS_htons(ETH_PORT);
xServerAddress.sin_addr = FreeRTOS_inet_addr(SPC5_ETH0_IP_ADDR ); // Indirizzo IP del server
//ret_socket = FreeRTOS_bind( xClientSocket, &xServerAddress, sizeof( xServerAddress ) ); 
//ret_addr = FreeRTOS_GetRemoteAddress(xClientSocket, &xClientAddress );
do {
    vTaskDelay(pdMS_TO_TICKS(750)); // Attende prima di ritentare
    ret_connect = FreeRTOS_connect(xClientSocket, &xServerAddress, sizeof(xServerAddress));
} while (ret_connect < 0);
for (;;)
{
    xSentBytes = FreeRTOS_send(xClientSocket, cBuffer, strlen(cBuffer), 0);
    //configASSERT(xSentBytes == strlen(cBuffer));
    vTaskDelay(pdMS_TO_TICKS(1000)); // Invia il messaggio ogni 500 ms
} }

The BINDTODEVICE sockopt is an added opt which does the following:

	case FREERTOS_SO_BINDTODEVICE:
		{/* Bind this socket to a particular device like "eth0". */
			const char * pxIfName = ( const char * ) pvOptionValue;
			if( pxIfName == NULL )
			{
				xReturn = -pdFREERTOS_ERRNO_EINVAL;
			}else{
				NetworkInterface_t * pxNetIf = FreeRTOS_GetIfByName( pxIfName );
				if( pxNetIf == NULL)
				{
					xReturn = -pdFREERTOS_ERRNO_EINVAL;
				}else{
					pxSocket->ulLocalAddress = pxNetIf->ulDefaultIPAddress;
					xReturn = 0;
				}}}
		break;

My nodes does not communicate, because Server Recv always returns Error:-22
Does anybody see any errors?

@SRomeo

Are you using multiple network interfaces on a single board?

The BINDTODEVICE sockopt is an added opt which does the following

Why is that required to be added? The existing FreeRTOS_bind binds the socket to an endpoint based on the sin_addr field of the xBindAddress, here.
If you have multiple endpoints and want your socket to bind to a particular endpoint, you may use the address of that endpoint.

xSentBytes = FreeRTOS_send(xClientSocket, cBuffer, strlen(cBuffer), 0);

strlen is designed for null-terminated strings (character arrays). Using it with a byte array like this will lead to undefined behavior, as it will keep reading memory until it finds a null byte (0).

Also, did you verify that both the boards are up and running and are responding to pings?
You can take a look at the sample TCP server and client application demos if you haven’t already.

While you debug further, you can enable FreeRTOS+TCP debug logs [example] and share. It will be good to have logs on the application as well to see if new connections are accepted or the socket got connected.

No, I’m not. Each board uses one network interface. Even if 2 network interfaces are present.

I need to bind my low level drivers controlling PHY to FreeRTOS operations. So my network_cfg.h was configured as follows:

#define SPC5_ETH0_PLCA_EN              TRUE
#define SPC5_ETH1_PLCA_EN              TRUE
#define SPC5_ETH0_PLCA_NCNT            2
#define SPC5_ETH1_PLCA_NCNT            2
#define SPC5_ETH0_PLCA_ID              1
#define SPC5_ETH1_PLCA_ID              0
.
:
#define spc5_eth0_netdrv_init(val)     dwmac_netdrv_init(val)
.
:
#define spc5_eth1_netdrv_init(val)     lan8650_netdrv_init(val)
.
:

Yes, both boards are operational, debugging smoothly. Moreover, individual perhipheral loopback is also working fine.

But, when trying TCP ethernet communication between 2 boards, I wasn’t able to pass through the accept/connect phases.


This is the state of my server a moment before exiting the BINDTODEVICE opt. And pxSocket is the resulting socket.

did you verify that network connectivity works at all, ie are you able to ping the devices from a third machine in the same subnet?

I verified that network connectivity works by enabling both “eth” peripheral and performing a closed-loop TCP communication. Which works.

Now I need to enstablish the communication between 2 boards.
Any suggestions related my Issue?
Is the client/server main task structure or operational flux wrong?

so I assume you are using the same TCP code for your loopback test that fails for remote? Or is it different?

Yes, it is the same except the fact client and server codes are split between 2 boards.
the “Server” board uses the eth0 PHY (ip 192.168.1.1) port 5555
the “Client” board uses the eth1 PHY (ip 192.168.1.2) port 5555

from a short grep over the sources it appears that -22 means EINVAL which for freertos_recv means that the socket is not bound properly. You may want to experiment with leaving out the BINDTODEVICE option and see if it makes a difference (cf also comment made by @tony-josi-aws ).

Already done, no difference

canyou single step into the freertos_recv call and see why the EINVAL return is generated (it comes relatively early in the code path)?

The top one is the state of the server, immediately after the execution of the recv.
Maybe I’m wrong but I expect sin_port and sin_addr to be different (192.168.1.1 and 5555)

And the bottom one is the state of the Client, a step after the connect.
Do you see anything?

well, I meant for you to step INTO freertos_recv to figure out what condition leads to the -22 return.

Don’t trust local variables in debugger windows, probably their locations have been reused.

Local variables un-trustable during the execution of a task?
The green highlight refers to where we have stopped, so, what you see on the right are just the last modified value of local variables, assigned by local functions.

Moreover, as you see, client’s CONNECT returns -116

Anyway, here the receive:

No, if the container for a local variable is being reused (because the variable is temporarily or permanently unused in the scope), the container (register, stack location…) will have something else in it. Nothing the debugger can do about that. You need to study the assembler code to determine if you can trust the local.

But back to business: If the local variables can be trusted, then pxSocket is a NULL pointer which is not right. There may have been a timeout on the accept call - see return value discussion here: FreeRTOS_accept() - FreeRTOS™ . You need to check the return of accept() against both FREERTOS_INVALID_SOCKET and NULL.

1 Like

In the server code you shared previously in the [first post],(FreeRTOS + TCP - Client Server communication Fail) you are checking for the validity of the socket returned by FreeRTOS_accept but it only checks for FREERTOS_INVALID_SOCKET:

Since you have set your xListeningSocket’s FREERTOS_SO_RCVTIMEO to 1 second:

FreeRTOS_setsockopt(xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &acpt_tout, sizeof(acpt_tout));

But in the debug screen capture you shared in the previous post, there is no check at all inside the server code.

If a timeout (FREERTOS_SO_RCVTIMEO) occurs before a connection from a remote socket is accepted, then NULL is returned by FreeRTOS_accept.

So you also need to verify the xConnectedSocket is not NULL as you set FREERTOS_SO_RCVTIMEO to be 1 second. In the demo code for server that I shared here before, FREERTOS_SO_RCVTIMEO is set to portMAX_DELAY which means the FreeRTOS_accept waits indefinitely and therefore never times out.

1 Like