FreeRTOS+TCP Windows Simulation - FreeRTOS_send() and FreeRTOS_rev() not working

I am building solution for a project on Coursera, where I have to send many long int arrays from a client to a TCP server. Sockets on both side are already settup, connection established with FreeRTOS_accept() from server side.

The problem is that after the first successful FreeRTOS_send() which return a possitive number of bytes of around 1000, it keeps returning -28. Does sending long int array instead of char mess up the return of the function?

Another thing is FreeRTOS_rev() from the server side does not return at all. Digging further revealing that the received bytes is 0, and the server is kept looping at line 2299 of FreeRTOS_Sockets.c, which is:

/* Block until there is a down-stream event. */
				xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
					eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR,
					pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );

Appreciate any suggestions. Thanks everyone.

Do you know if the call to FreeRTOS_send() actually results in bytes going out on the wire? You can tell that by using Wireshark to view the network traffic.

Did you follow the ‘software setup’ steps on this page? https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html

The first think to ensure if that you are using an Ethernet port rather than a Wi-Fi port (you can use an Ethernet to Wi-Fi adapter, or a virtual Ethernet port if the network traffic is all local to your computer) and that configNETWORK_INTERFACE_TO_USE is set correctly to the Ethernet interface.

When an API returns a negative value, you can look it up in FreeRTOS_errno_TCP.h, which is much the same as errno.h.

So -28 means: pdFREERTOS_ERRNO_ENOSPC: “No space left on device”.

I would also recommend running WireShark to see what is sent. Maybe your application does send data, but it doesn’t get an acknowledgement?

True, the third handshake ACK from the client doesn’t reach the server.

I made sure to follow all the steps from the tutorial Richard suggested. The network is one created within Virtualbox, and I can ping both the client and server from Windows Command Prompt. But now networking is something I’m lacking knowledge of :frowning:

This task will be launched from vApplicationIPNetworkEventHook() on the server side:

void socket_init(void)
{
	if (xMustCreateSockets != pdFALSE)
	{
		xMustCreateSockets = pdFALSE;

		/* Attempt to open the socket. */
		xListeningSocket = FreeRTOS_socket(PF_INET,
			SOCK_STREAM,  /* SOCK_STREAM for TCP. */
			IPPROTO_TCP);

		/* Check the socket was created. */
		configASSERT(xListeningSocket != FREERTOS_INVALID_SOCKET);

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

		/* Reuse socket for receiving data*/
		BaseType_t xReuseSocket = pdTRUE;
		FreeRTOS_setsockopt(xListeningSocket,        
			0,
			FREERTOS_SO_REUSE_LISTEN_SOCKET,
			(void*)&xReuseSocket,
			sizeof(xReuseSocket));

		/* Set the listening port to 7312. */
		xBindAddress.sin_port = (uint16_t)7312;
		xBindAddress.sin_port = FreeRTOS_htons(xBindAddress.sin_port);

		/* Bind the socket to the port that the client RTOS task will send to. */
		FreeRTOS_bind(xListeningSocket, &xBindAddress, sizeof(xBindAddress));

		/* Set the socket into a listening state so it can accept connections.
		The maximum number of simultaneous connections is limited to 20. */
		FreeRTOS_listen(xListeningSocket, xBacklog);

		//for (;; )
		{
			/* Wait for incoming connections. */
			xConnectedSocket = FreeRTOS_accept(xListeningSocket, &xClient, &xSize);

			printf("CLIENT CONNECTED\n");

			configASSERT(xConnectedSocket != FREERTOS_INVALID_SOCKET);

			/* Spawn a RTOS task to handle the connection. */
			xTaskCreate(prvEchoClientRxTask,
				"EchoServer",
				65530,
				(void*)xConnectedSocket,
				3,
				NULL);
		}
	}
}

The prvEchoClientRxTask() function’s content is the same as https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Networking_Tutorial_Receiving_TCP_Data.html albeit with long buffer instead of char.

The client side also have a similar task, but I’m keeping the socket as global variable, not sure if anything is affected. I expect only 1 client to connect to 1 server.

void socket_init(void)
{
	if (xMustCreateSockets != pdFALSE)

	{

		xMustCreateSockets = pdFALSE;

		/* Set the IP address (192.168.56.234) and port (7312) of the remote socket
			to which this client socket will transmit. */
		xRemoteAddress.sin_port = FreeRTOS_htons(7312);
		xRemoteAddress.sin_addr = FreeRTOS_inet_addr_quick(192, 168, 56, 234);

		//while (xTasksAlreadyCreated == pdFALSE) printf("still false");
		/* Create a socket. */
		xSocket = FreeRTOS_socket(FREERTOS_AF_INET,
			FREERTOS_SOCK_STREAM,/* FREERTOS_SOCK_STREAM for TCP. */
			FREERTOS_IPPROTO_TCP);
		configASSERT(xSocket != FREERTOS_INVALID_SOCKET);
		/* Connect to the remote socket.  The socket has not previously been bound to
	a local port number so will get automatically bound to a local port inside
	the FreeRTOS_connect() function. */
		if (FreeRTOS_connect(xSocket, &xRemoteAddress, sizeof(xRemoteAddress)) == 0)
		{
			printf(("CONNECTED TO SERVER, BEGIN SENDING DATA\n"));
			xTaskCreate(vTCPSend,"Sending",65530,NULL,3,NULL);
		}
	}
}

This task will be launched from vApplicationIPNetworkEventHook()
on the server side

Does that mean that your socket_init() is running from the network event hook?
The only thing to do within a vApplicationIPNetworkEventHook() is create a task, or set a variable, but you should not call any FreeRTOS+TCP API, because it is called from the IP-task.

I often have this kind of hook:

static BaseType_t xCreateSockets = pdFALSE;

void vApplicationIPNetworkEventHook( void )
{
    static BaseType_t xFirstTime = pdTRUE;

    if( eNetworkEvent == eNetworkUp )
    {
        if( xFirstTime == pdTRUE )
        {
            xFirstTime = pdFALSE;
            /* xCreateSockets will be monitored in a task. */
            xCreateSockets = pdTRUE;
            /* Wake up the server task. */
            xTaskNotifyGive( xServerWorkTaskHandle );
        }
    }
}

In your server code, you are using the option FREERTOS_SO_REUSE_LISTEN_SOCKET. I would recommend not to use it until you have read all documentation about it. It is a very non-standard way of implementing a TCP server.

Before calling FreeRTOS_connect(), you should set the send timeout: FREERTOS_SO_SNDTIMEO.
Before calling FreeRTOS_accept(), you should set the reception time-out FREERTOS_SO_RCVTIMEO.

In more advanced applications, where multiple sockets are handled with a single task, both connect() and accept() can be used in non-blocking ways, and a time-out of zero.

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
...
static BaseType_t xTasksAlreadyCreated = pdFALSE;

	/* If the network has just come up...*/
	if( eNetworkEvent == eNetworkUp )
	{
		xMustCreateSockets = pdTRUE;

		/* Create the tasks that use the IP stack if they have not already been
		created. */
		if( xTasksAlreadyCreated == pdFALSE )
		{
			...
			xTaskCreate(socket_init,"Socket_Init",100,NULL,1,NULL);

			xTasksAlreadyCreated = pdTRUE;
		}
        ...
	}
}

My network event hook is like this.
And aren’t the timeout durations default to 5 seconds if we don’t set it?
Also I’m sorry I forgot to mention that I have to use FreeRTOS version 9.0.1 for this project. I’m also not going to work on this project anymore, so this thread can be closed. Thank you Hein and Richard for your help :smiley: