Discussion:
[libtorrent] multi-home plans
Steven Siloti
2016-11-14 00:55:06 UTC
Permalink
I've been pondering how to handle multi-home operation and here's what I'm
planning on:

For IPv4, multi-home will only be supported if the user explicitly
specifies multiple IPv4 address to listen on. The default behavior will
still be to bind to 0.0.0.0 and treat that as a single host.

Binding a listen socket to :: will be prohibited unless we cannot enumerate
network interfaces. If we can enumerate the interfaces and :: is found in
the listen_interfaces setting, then we will bind to every enumerated IPv6
address. Any specific listen_interface entries will be bound first so that
device bindings are honored[0].

reopen_listen_sockets() will be changed to retain existing listen_socket_t
instances if they are still valid. The session_impl will send notifications
to the DHT, UTP, and UDP tracker subsystems indicating when a specific
listen socket is added or removed.

The external_ip struct will be changed to support a single address family
per instance. Each listen socket will get it's own instance of external_ip.
These will be initialized with the bound address.

For each address family there will be a pointer to an external_ip in
session_impl which points to the external_ip of one of:

1. An arbitrarily selected global scope listen socket
2. The listen socket bound to the unspecified address
3. An arbitrarily selected local scope listen socket

This is only intended to be used for computing peer priority, for which I
don't think there is a good solution wrt multi-home.

UTP connections will be associated with a specific socket and will
exclusively send/receive packets using that socket. Incoming UTP
connections will be associated with the listen socket the SYN was received
on.

For outgoing UTP connections, the session_impl will maintain a set of
one-or-more outgoing UDP sockets created in accordance with the
outgoing_interfaces setting. New connections will be assigned to one of
these sockets in a round-robin fashion, similar to what is done with
outgoing TCP connections.

The DHT tracker will create a separate node instance for each listen socket
that is bound to either an unspecified address, an IPv4 address, or a
global IPv6 address. Nodes will be added/removed in response to the listen
socket notifications from session_impl.

Tracker announces will be sent using every bound listen address or
external_ip that has the same scope as the destination address.

session_impl::listen_port(), ssl_listen_port(), and external_udp_port()
will be modified to rotate through the listen sockets rather than always
reporting the first one. Most calls to these functions will be removed. I
expect the calls to set the port in the extension handshake and the
dht_port message will remain though.

LSD will send separate announcements for each listen socket.

Does all this seam reasonable? Did I miss anything? Clearly this is a huge
amount of work so I don't expect it will happen all at once. I'm going to
try to break it up into pieces which can be merged incrementally. Removing
binding to :: by default is going to have to come last since it would break
a lot of the non-multi-home aware code.

[0] Is there any reason not to bind all enumerated addresses to their
respective devices?
Steven Siloti
2016-11-14 16:19:57 UTC
Permalink
Actually, we can probably get rid of listen_port() et. al. entirely. The
ports we report on peer connections will be selected based on the
connection's local address.
Post by Steven Siloti
I've been pondering how to handle multi-home operation and here's what I'm
For IPv4, multi-home will only be supported if the user explicitly
specifies multiple IPv4 address to listen on. The default behavior will
still be to bind to 0.0.0.0 and treat that as a single host.
Binding a listen socket to :: will be prohibited unless we cannot
enumerate network interfaces. If we can enumerate the interfaces and :: is
found in the listen_interfaces setting, then we will bind to every
enumerated IPv6 address. Any specific listen_interface entries will be
bound first so that device bindings are honored[0].
reopen_listen_sockets() will be changed to retain existing listen_socket_t
instances if they are still valid. The session_impl will send notifications
to the DHT, UTP, and UDP tracker subsystems indicating when a specific
listen socket is added or removed.
The external_ip struct will be changed to support a single address family
per instance. Each listen socket will get it's own instance of external_ip.
These will be initialized with the bound address.
For each address family there will be a pointer to an external_ip in
1. An arbitrarily selected global scope listen socket
2. The listen socket bound to the unspecified address
3. An arbitrarily selected local scope listen socket
This is only intended to be used for computing peer priority, for which I
don't think there is a good solution wrt multi-home.
UTP connections will be associated with a specific socket and will
exclusively send/receive packets using that socket. Incoming UTP
connections will be associated with the listen socket the SYN was received
on.
For outgoing UTP connections, the session_impl will maintain a set of
one-or-more outgoing UDP sockets created in accordance with the
outgoing_interfaces setting. New connections will be assigned to one of
these sockets in a round-robin fashion, similar to what is done with
outgoing TCP connections.
The DHT tracker will create a separate node instance for each listen
socket that is bound to either an unspecified address, an IPv4 address, or
a global IPv6 address. Nodes will be added/removed in response to the
listen socket notifications from session_impl.
Tracker announces will be sent using every bound listen address or
external_ip that has the same scope as the destination address.
session_impl::listen_port(), ssl_listen_port(), and external_udp_port()
will be modified to rotate through the listen sockets rather than always
reporting the first one. Most calls to these functions will be removed. I
expect the calls to set the port in the extension handshake and the
dht_port message will remain though.
LSD will send separate announcements for each listen socket.
Does all this seam reasonable? Did I miss anything? Clearly this is a huge
amount of work so I don't expect it will happen all at once. I'm going to
try to break it up into pieces which can be merged incrementally. Removing
binding to :: by default is going to have to come last since it would break
a lot of the non-multi-home aware code.
[0] Is there any reason not to bind all enumerated addresses to their
respective devices?
--
Steven Siloti <***@gmail.com>
Loading...