sccn / liblsl

C++ lsl library for multi-modal time-synched data transmission over the local network
Other
107 stars 63 forks source link

`allow_random_ports`: Let the OS choose an open port #147

Closed tstenner closed 2 years ago

tstenner commented 2 years ago

When all configured ports are bound and allow_random_ports is enabled, liblsl can try random ports to bind a socket to a port outside the configured range.

This PR changes the socket binding code to open port 0, i.e. let the OS find an open port or abort immediately if there's no free port or no interface to bind to (e.g. as seen in #45).

cboulay commented 2 years ago

Can you point to any documentation that states using port 0 will allow the OS to find an open port?

I ran into a dead end from the official docs: https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload2.html

tstenner commented 2 years ago

I ran into a dead end from the official docs: https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload2.html

It's not in the Asio docs, but the Asio docs leave out a lot of the underlying transports.

For Windows, it's in the documentation for the bind() function:

For TCP/IP, if the port is specified as zero, the service provider assigns a unique port to the application from the dynamic client port range.

For Linux, it's a bit scattered, but documented in multiple places:

man ip(7):

ip_local_port_range (since Linux 2.2) This file contains two integers that define the default local port range allocated to sockets that are not explicitly bound to a port number—that is, the range used for ephemeral ports. An ephemeral port is allocated to a socket in the following circumstances:

         *  the port number in a socket address is specified as 0
            when calling bind(2);

man bind(2)

IP_BIND_ADDRESS_NO_PORT (since Linux 4.2) Inform the kernel to not reserve an ephemeral port when using bind(2) with a port number of 0.

and

ERRORS EADDRINUSE (Internet domain sockets) The port number was specified as zero in the socket address structure, but, upon attempting to bind to an ephemeral port, it was determined that all port numbers in the ephemeral port range are currently in use.

And, somewhat hidden, in the BSD socket API documentation:

IP_PORTRANGE may be used to set the port range used for selecting a local port number on a socket with an unspecified (zero) port number. It has the following possible values:

cboulay commented 2 years ago

I hope Mac works the same way. I don't think it's an often used feature so we'll probably never get any complaints even if it doesn't.