libsdl-org / SDL_net

A simple, cross-platform wrapper over TCP/IP sockets.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Compound Addresses (and sockets?)

sulix opened this issue · comments

It's quite common to want to listen on, or connect to machines with multiple addresses. For the former, we can use NULL as an address, which does work as an API to binding on everything (though the implementation is not super-robust yet, see below), but for the latter, SDL_ResolveHostname() can only return a single SDL_Address, so only one of the addresses associated with the hostname can be retrieved.

This can cause problems if some of the addresses associated with the hostname are not reachable (e.g., a site has an IPv6 AAAA record, but the local machine only has a link-local IPv6 address). Equally, it makes it more complicated to listen on a subset of the local addresses (e.g., I want to listen on all addresses associated with one interface.).

One solution I've used in the past is to have "compound addresses", where there's a native "address list" type, and sockets can be bound to multiple addresses (possibly using several sockets behind the scenes, if required). As a bonus, this "address list" could also be an SDL_Address (give it a next pointer to turn it into a linked list, for example), and then the rest of the public API could remain the same.

In addition, it seems that the current implementation of using NULL/AF_UNSPEC to bind on all addresses doesn't always work (e.g., on my machine it'll bind to all addresses of the same family, such as all IPv4 addresses or all IPv6 addresses, but not both). Getting a truly reliable listener for both IPv6 and IPv4 has required setting up two separate sockets with the different address families (and using the V6ONLY option if family if AF_INET6 to prevent double-binding to compatibility addresses). Having multiple sockets backing a single visible socket would require a similar sort of "compound socket".

There'd be a lot of subtlety in getting this right, though: it's pretty straightforward to bind or listen on multiple addresses, but it gets more complicated when connecting / sending (do you send to all addresses, just the first one, a random one, implement some sort of retry logic until one works)? For the most part, it comes together pretty obviously for TCP/stream sockets, but UDP/datagram ones are a bit more ambiguous.

Does this seem like a useful idea, or just too much added complexity, in either the API or implementation? If so, I can experiment with a more concrete proposal.

I think it's too much complexity that most things aren't going to use.

The exception is talking to both IPv4 and IPv6 at the same time, and the usual solution is to use a dual-stack socket by turning off the IPV6_V6ONLY flag, which allows IPv4 addresses map into the IPv6 address space. Linux defaults to this being off, WinSock defaults to it being on, and SDL_net is not explicitly setting it at the moment and probably should.