Does FreeRTOS_bind() supports binding to multiple IP addresses of the device on which it is running, so that TCP/IP server can listen for incoming connections from multiple IP address?
We have two ethernet ports on our device having ST Micro Controller (STM32F722RE)
We are using FreeRTOS+TCP Multi.
Its expected that the application running on this device shall be listening on both ethernet ports of the device (I.e. two different IP addresses) from multiple clients.
We are developing a TCP/IP server which will be running on this device. This server will be listening for incoming connections from multiple clients.
Should we have to create two different (server) sockets which will be listening for incoming connections on multiple IP addresses (of a device)?
We have to create ony one (server) socket which can listen for incoming connection on two multiple IP addresses (of a device)?
As per my understanding “bind()” API in windows and linux supports “INADDR_ANY”, I.e. When INADDR_ANY is specified in the bind call the socket will be bound to all local interfaces.
Does FreeRTOS_bind() supports the same feature? So that we can have only one server socket which which will be listening for incoming connections on multiple IP addresses (of same device)?
Any input, clarification regarding this will be helpful.
We have decided to always use the
INADDR_ANY approach, it means that you can have only one server socket listening to a particular port number. I will accept TCP connections from any other IP-address.
So in fact the
sin_addr member of
struct freertos_sockaddr is ignored.
In order to keep your code compatible with other platforms, I would recommend writing the following code:
struct freertos_sockaddr xBindAddress;
memset( &( xBindAddress ), 0, sizeof( xBindAddress ) );
xBindAddress.sin_len = sizeof( xBindAddress );
xBindAddress.sin_family = FREERTOS_AF_INET;
xBindAddress.sin_port = FreeRTOS_htons( 80 );
xBindAddress.sin_addr = FREERTOS_INADDR_ANY;
BaseType_t xRc = FreeRTOS_bind( xSocket, &( xBindAddress ), sizeof( xBindAddress ) );
sin_len is also ignored. When IPv6 is enabled, the size of
freertos_sockaddr6 is the same as the size of
freertos_sockaddr. because of that, it is safe to interpret
freertos_sockaddr6 and v.v.
Here above IPv4 is chosen, but the server will also accept IPv6 connections.
So the answer to your question is: one server per port number.
Thanks for your input.
With the code snippet and description you have specified, my understanding is : FreeRTOS bind() API also supports “INADDRA_ANY”. With this we will need only one server to be in listening mode for multiple IP addresses of the device.
E.g. If my device is having 2 IP address and port as follows:
- IP address 192.168.1.5 port 502 for Ethernet port-1
- IP address 192.168.2.5 port 503 for Ethernet port-2
With the code snipped you have specified, single socket socket will be bind to both the IP Address and ports specified above.
Is my above understanding correct? Your confirmation will be very helpful.
I am still working on the input you have given on IPv6. I will get back to you on IPV6.
As Hein mentioned you need 1 server socket per port.
E.g. If my device is having 2 IP address and port as follows:
IP address 192.168.1.5 port 502 for Ethernet port-1
IP address 192.168.2.5 port 503 for Ethernet port-2
A device does not have a port number. A service has a port number, like HTTP usually has port number 80. You only need to create a single HTTP server that will accept connections from all end-points.
Your device seems to get 2 end-points:
IP 192.168.1.5 Mask 255.255.255.0 GW x.x.x.x DNS x.x.x.x
IP 192.168.2.5 Mask 255.255.255.0 GW 0.0.0.0 DNS 0.0.0.0
Here is some more text about multiple interfaces and end-points.
interfaces_multiple_v1.zip (107.4 KB)
Hi Hein Tibosch and Hartmut Schaefer
Thanks for your replies. “interfaces_multiple_v1.pdf” is helpful to understand the concept.
Hein: I agree with you that the device don’t have the port number associated. A service will have port number associated with it (port is nothing but a logical entity).
Yes, you are right. Our device is having 2 different end-points. I.e. 2 different physical Ethernet ports. Each Ethernet port is having its unique IP address. (I.e. the device is having 2 different IP address altogether)
Now, from the description it appears to me that we need to create a only one server socket which can accept “connections” from multiple end-points (In our case 2 physical Ethernet ports).
For that we need to:
- Use “FREERTOS_INADDR_ANY” in FreeRTOS_bind() API, as you have specified above.
- Use FreeRTOS_listen() on this socket.
- use FreeRTOS_accept() on this socket, for accepting incoming connections on both IP address
Can you please confirm whether above understanding is correct or not?
[Note: Please accept my apologies for repetitive question.]
That all looks good to me!
Note that listen() has a parameter
xBacklog. That determines the maximum number of TCP clients that you allow to connect to the server. Zero would mean : until running out of resources. I would recommend giving it a reasonable value depending on your needs.
Hi Hein Tibosch,
Thanks for confirming the understanding.
Yes, we do have a plan to set a limit on “xBacklog” to 10 to start with. With this I am expecting that the socket will accept/keep maximum 10 simultaneous active connections. After 10 active clients, for 11th client the connection will be automatically refused. We need not write a code for this.
I really appreciate your inputs and patience in answering the question.
In the same context, now I have question about the port number (IP Address:Port combination) to be used.
For both IP address:
- Can port numbers numbers be different or should they be same?
- If both ports can be different then how they should be specified?
You should find some more background information about TCP networking.
There are plenty of really good resources in the net. First it looks simple, but when going into details implementing a real world, robust application the fun starts
listen backlog parameter specifies the maximum number of simultaneously pending connects. It doesn’t limit the number of the (accepted and existing) TCP connections. It’s up to the application writer to count/limit the supported simultaneous connections (usually depending on available system resources especially memory).
This means in your case you should stop listening after accepting the 10. connection and restart listening when the number of connections drops below 10 (because a connection was closed or got broken).
As mentioned a networking service is specified by its associated port number.
If you offer 2 different networking services you have to listen for incoming connections from 2 ports. That means you need 2 server sockets.
For example an application offers 1 control service to receive commands from a connected client and send back confirm messages and 1 data service e.g. to send measurement results to a connected client.
This application needs 2 server sockets listening to 2 different ports.
That is indeed the official meaning of the parameter
int listen(int sockfd, int backlog);
In an embedded application however, we thought it would be more important to limit the actual number of connections. If not, it would be too easy to flood the device with SYN requests, each one creating a new child socket.
Sorry, I pressed Send too quickly.
This means in your case you should stop listening after accepting the 10. connection and
restart listening when the number of connections drops below 10
When a TCP server socket on port 80 is in a listening state, it will get a child socket each time a valid connection request for port 80 is received.
Even when the application is too busy to call
accept(), the system will make sure that no more than
backlog child sockets will be created.
( I thought it would be a complex task for an application builder to count the number of connections, and temporarily close a socket when there are too many connection, one would be too late ).
UDP also has the same kind of protection: when
ipconfigUDP_MAX_RX_PACKETS is defined as a positive number, the number of UDP packets stored in a socket will be limited to that amount.
I hope that the misunderstandings have been cleared now. Maybe we should have renamed the word
Thanks for the explanation Hein ! The modified behavior would indeed make sense for embedded applications.
To be really sure the stack ensures that there will be no more than
max_connections pending and accepted connections (if the listen socket is not reused) ? Are exceeding connect attempts replied with RST ?
I thought SYN flooding is partially mitigated by limiting the allowed pending connections.
I currently don’t have the sources at hand so I just ask
To be really sure the stack ensures that there will be no more
than backlog/max_connections pending and accepted connections
(if the listen socket is not reused) ? Are exceeding connect
attempts replied with RST ?
Correct. Any incoming SYN request will either be accepted and passed to accept(), or it will be dropped and responded to with a RST packet, which leads to a “connection refused” on the remote device.
The memory costs of a TCP connection is “deterministic”: a socket will be allocated, and two fixed-size stream buffers, one incoming and one outgoing.
In the end we want operations that have no surprises but a predictable claim on the heap. Here is a tool that gives a live insight into the memory claims for TCP/UDP sockets: tcp_mem_stats.c.
I thought SYN flooding is partially mitigated by limiting the
allowed pending connections. I currently don’t have the
sources at hand so I just ask
That is how other stacks ( Linux / Windows ) have implemented it. We chose simplicity and predictability. The TCP door is either open or closed, and there is no waiting queue.
Note that some applications only allow a single TCP client. In that case the socket option
FREERTOS_SO_REUSE_LISTEN_SOCKET can be used. When a SYN comes in, the server socket turns into a client socket. After the conversation, the client socket must be closed and a new server socket must be created. This is also the most economic solution, it saves the creation of 1 socket.