FreeRTOS+TCP multi use and examples

claudiorossi wrote on Monday, August 27, 2018:

Hi

I have created a project based on Zynq platform with FreeRTOS+TCP multi, but I don’t found any documentation or example about the use of it.
I’m new to FreeRTOS and TCP and i need some helps to start.
Are there some documentations or examples on the web?

Thanks for help

kenchang1 wrote on Wednesday, August 29, 2018:

There are some examples here: https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Networking_Tutorial.html
Also, it might be useful to read about Berkeley sockets (use google).

Good luck.

claudiorossi wrote on Wednesday, August 29, 2018:

Hi Ken

I know this tutorial and I’m using it to test my ethernet port; but my board has two
ethernet port and the FreeRTOS+TCP can only manage a single port (i think).
In FreeRTOS+TCP download page i found the ‘180222-freeRTOS-plus-TCP-Multi.zip’ file that
contains TCP source files to manage more than one ethernet port.
Unfortunately in this file there are not documentation nor example.

kenchang1 wrote on Wednesday, August 29, 2018:

I see what you mean. Some time ago I have received some test code (with zynq_main.c) from Hein Tibosch. I have used this test code as a starting point. I think Hein can provide you this zynq_main.c test code. The version I have is not up to date.

heinbali01 wrote on Thursday, August 30, 2018:

Hi Claudio, I’m sorry that it takes so much time before FreeRTOS+TCP /multi comes out officially, but eventually it will!
It is true that there is no documentation yet. The library has been well tested though, especially by Ken Chang, who is replying here above. He did not make use of IPv6 though, only IPv4.

I will attach 3 files:

FreeRTOS-Plus-TCP_multi_30_aug_2018.7z : the latest sources, which are only slightly different from the /multi release on freertos.org/tcp

plus_tcp_multi_v2.pdf : a short description of what makes /multi different

zynq_main.c : an example that uses multiple NIC’s

Please define ipconfigMULTI_INTERFACE in your FreeRTOSIPConfig.h, if you want to use the /multi software.

I have some projects for testing that can either be linked with the normal FreeRTOS+TCP library, or with FreeRTOS+TCP /multi, depending on the value of ipconfigMULTI_INTERFACE, 0 or 1.

If you have any questions, please ask them in this post.

claudiorossi wrote on Thursday, August 30, 2018:

Hi Hein and hi Ken

Thanks a lot for your help.
Now i am working on a single port using +TCP in order to understand the TCP library (i am new to the argument), then i will try to use multi library with the second ethernet port.

Best regards

heinbali01 wrote on Thursday, August 30, 2018:

Now i am working on a single port using +TCP in order to understand the TCP library

Sounds good. Remember that ipconfigMULTI_INTERFACE can be helpful to make the transition from single to multi more gradual

claudiorossi wrote on Thursday, August 30, 2018:

Hi Hein
I toke a look in zynq_main.c file and I understood the initialization sequence. Now my question is about the instantiation of one or more sockets.
Do i need to use the standard TCP functions (FreeRTOS_socket, FreeRTOS_bind, etc)?
If yes, how can i create a socket for a particular ethernet channel?
If I call FreeRTOS_socket(), the socket is connected to ethernet #0 or ethernet #1?
I do not find the connection point between the standard TCP library funtions and the data structures used to manage multi interface.

Thanks and best regards

heinbali01 wrote on Thursday, August 30, 2018:

Hello Claudio, we have tried to make the change to /multi as intuitively as possible.

Sockets are not bound to a particular interface, with the exception of TCP sockets that are connected with a peer.

On a laptop, I can bind several sockets to the same port number, for instance:

    Socket 1: 192.168.2.5 port 23   // LAN
    Socket 2: 36.75.115.247 port 23 // Internet
    Socket 3: 10.0.5.112 port 23    // WiFi

When I put each socket in listening mode, they will each receive connections on their network.

Another way to go is bind a sockt to 0.0.0.0, which stands for “any network”.
That is the way to go in FreeRTOS+TCP /multi. Every ( UDP or TCP ) port can only be bound once:

    Socket 1: 0.0.0.0 port 23   // LAN + Internet + WiFi

When the following statement succeeds:

	struct freertos_sockaddr xAddress;
    Socket_t xSocket = FreeRTOS_accept( xServerSocket, &xAddress, ( socklen_t )sizeof xAddress );

the connected socket xSocket will only use the network interface that leads to it’s peer.

About UDP : when sending ( or replying to ) a packet, the stack will find the best matching interface. For broadcast packets, all interfaces will be addressed.

In short: the application will not change much when moving from +TCP /single to /multi

claudiorossi wrote on Friday, August 31, 2018:

Hi Hein
if I understand, the socket process is tied to port number instead to IP address, then I need to create a socket for each port I intend to use.
For example, in my case I have 2 port: the first at IP 192.168.0.0 and the second at 192.168.1.0.
The first port is used for the connection of a telnet client (port 23) and a HTTP client (port 80), while the second port for a FTP client (port 21).
So I need to do the following:

  1. Create 2 network interface and 2 network node.
  2. Call FreeRTOS_IpStart function
  3. Create a socket set (FreeRTOS_CreateSocketSet).
  4. Create my 3 socket (for telnet, HTTP, FTP) and initialize them (_bind, _setsockopt, _listen)
  5. Add sockets with FreeRTOS_FD_SET().
  6. Create a process(loop) for socket acceptation for each of my sockets (FreeRTOS_accept)

If a connection is requested to a port then FreeRTOS_accept function return a socket structure pointer for this connection.
Is my procedure correct?

But if I connect the FTP client to port 0 (instead of port 1) and try to connect the client to 192.168.0.0:21, the FreeRtos_accept function will accept the connection?
If yes, if I want to know the IP address of my connection in order to distinguish the port (and eventually write an error message) can I use the address structure filled by FreeRTOS_accept function?

I hope I was clear in my exposition.
Thanks and best regards

heinbali01 wrote on Friday, August 31, 2018:

Hi Claudio,

if I understand, the socket process is tied to port number instead to
IP address, then I need to create a socket for each port I intend to use.

Indeed, you create a socket for each port number and not for each IP-address + port-number combination.
Just like you would in +TCP /single.

For example, in my case I have 2 port: the first at IP 192.168.0.0 and the second at 192.168.1.0.

Those numbers are IP-addresses, not port numbers.

The first port ( HT: IP-address ) is used for the connection of a telnet client (port 23)
and a HTTP client (port 80), while the second port ( IP-address ) for a FTP client (port 21).

You will need 3 sockets and bind them to:

0.0.0.0 prt 23
0.0.0.0 prt 80
0.0.0.0 prt 21

So I need to do the following:

  1. Create 2 network interface and 2 network node

In the software the nodes are called end-points

The application defines one or more interfaces, and each interface can have one or more end-points ( or IP-addresses ).

  1. Call FreeRTOS_IPStart() function
  2. Create a socket set ( FreeRTOS_CreateSocketSet ).
  3. Create my 3 socket (for telnet, HTTP, FTP) and initialize them ( bind(), setsockopt(), x_listen() )
  4. Add sockets with FreeRTOS_FD_SET().
  5. Create a process(loop) for socket acceptation for each of my sockets ( FreeRTOS_accept() )

Looks all good

If a connection is requested to a port then FreeRTOS_accept() function return
a socket structure pointer for this connection.

True. FreeRTOS_accept() will return a new socket. Note that this socket will inherit all properties of the parent socket ( i.e. the listening socket ).
Once the connection is closed, the socket must be freed by calling FreeRTOS_closesocket().
It is important to set the buffer properties of the parent socket, because once a child-socket is receiving data, the receive buffer-size ( FREERTOS_SO_RCVBUF ) can not be changed any more.

Is my procedure correct?

Looks OK to me.

But if I connect the FTP client to port 0 (instead of port 1)

Where do you bind this socket? On a host?
Normally you bind a client socket to port 0, which means a random ( anonymous ) port number.
Binding to a low ( non-zero ) port number will most probably fail because they are reserved for the OS.

Normally:

● A server socket is bound to a well-known ( non-zero ) port number
● A client socket is bound to port number 0

But this rule is not obligatory.

One example: FTP in PASSIVE mode, opens a server socket for a data connection, which is bound to port 0 in order to get a random port number. The client will connect to this socket.

The server socket only expects a single client, so xBacklog equals 1:

FreeRTOS_listen( xServerSocket, 1 );

and try to connect the client to 192.168.0.0:21, the FreeRTOS_accept()
function will accept the connection?

Yes indeed.

Note that you can determine the maximum number of connected clients to a socket. See the second parameter of FreeRTOS_listen(): xBacklog.

If yes, if I want to know the IP address of my connection in order to
distinguish the port (and eventually write an error message) can I use
the address structure filled by FreeRTOS_accept() function?

Yes the parameter pxAddress of FreeRTOS_accept() will contain the address of the remote peer (in network-endian order).

claudiorossi wrote on Monday, September 03, 2018:

Hi Hein

Thank you for your response, now is more clear.

But if I connect the FTP client to port 0 (instead of port 1)

Where do you bind this socket? On a host?
Normally you bind a client socket to port 0, which means a random ( anonymous ) port number.
Binding to a low ( non-zero ) port number will most probably fail because they are reserved for the OS.

Normally:

● A server socket is bound to a well-known ( non-zero ) port number
● A client socket is bound to port number 0

But this rule is not obligatory.

About port mentioned in my post was my mistake, I meant physical port 0 and port 1.
On my board the TCP interface is the server and the board is connected to a windows based PC. On the PC I want to use telnet or filezilla or Web browser application for communication.

Moreover I get some compilation error (both in /single and /multi) if I compile a C++ based project, while in a C based project there are not problems.
I have modified the sources to correct the problem.
Example:
-file x_emacpsif_hw.c

void clean_dma_txdescs(xemacpsif_s *xemacpsif)
{
int index;
unsigned char *ucTxBuffer;

/* Clear all TX descriptors and assign uncached memory to each descriptor.
"tx_space" points to the first available TX buffer. */
ucTxBuffer = xemacpsif->tx_space;

for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
{
    xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
    xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
		// FIXME crs!!! modified for compilation error in c++
    pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;
    //pxDMA_tx_buffers[ index ] = ( void* )NULL;
#else
		pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );
#endif
		ucTxBuffer += xemacpsif->uTxUnitSize;
	}
	xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
		XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
}

-file x_emacpsif_hw.c

// FIXME crs!!! added include file for c++ compilation error
#include "NetworkInterface.h"

-file x_emacpsif_physpeed.c

// FIXME crs!!! added static (or move into Phy_Setup?) for c++ compilation error
//static unsigned link_speed;
unsigned Phy_Setup (XEmacPs *xemacpsp)
{
	unsigned long conv_present = 0;
	unsigned long convspeeddupsetting = 0;
	unsigned long convphyaddr = 0;
	unsigned link_speed;

Similar problem with FreeRTOS+FAT files:
ff_ioman.c in (function FF_BlockRead and FF_BlockWrite)

			// FIXME crs!!! aggiunto cast a pxBuffer per errori compilazione in c++
			slRetVal = pxIOManager->xBlkDevice.fnpReadBlocks((uint8_t*) pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk );

ff_file.c

static FF_FILE *prvAllocFileHandle( FF_IOManager_t *pxIOManager, FF_Error_t *pxError )
{
FF_FILE *pxFile;

  // FIXME crs!!! inserito cast (FF_FILE*) per errore compilazione in c++
	pxFile = (FF_FILE *)ffconfigMALLOC( sizeof( FF_FILE ) );

Best regards

Dear Hein,

Can you re-attach this files, please?
Thank you so much.

Claudio,

Attaching a ZIP file:

plus_tcp_multi.zip (155.6 KB)

You can find a recent copy of the /multi library here

1 Like