[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Adding ipv6 support.



Frank's advice is a great overview of how to approach the problem.
sockaddr_storage provides enough storage space for any
platform-supported socket family, but in some cases I've found it to
be too generous, much larger than sockaddr_in6, the largest I care
about.  Also, I don't like the typical casting to (struct sockaddr
*)&my_sockaddr_storage required by APIs which take struct sockaddr *
as the generic type.

If you only care about IPv4 and IPv6 sockets, consider using a union
of the useful types:

typedef struct union_saddr_tag {
    struct sockaddr            sa;
    struct sockaddr_in       sin;
    struct sockaddr_in6     sin6;
} union_saddr;

Then use union_saddr as your generic type, distinguishing variants
using sa.sa_family.  When calling functions that take a sockaddr *,
use &my_saddr.sa and no potentially-bug-hiding cast is required.

If you care about supporting all socket types, or have code that wants
sockaddr_storage * parameters, include a "struct sockaddr_storage
sas;" in the union.  Switching NTP to this approach uncovered one or
two bugs where in_addr/in6_addr pointers were being passed to macros
expecting sockaddr_storage, which were hiding the bugs with explicit
(struct sockaddr storage *) casts.

Another fine point in enabling client applications in particular for
IPv6 is address selection and parallel queries.  MacOS and Windows do
a pretty respectable (and configurable) job of ordering
getaddrinfo()'s result list, particularly with the subtle trade-offs
in originating from IPv6 automatic tunnel addresses using 6to4 and
teredo in the presence of native v4 or v6 alternatives.  On those
systems, you're less likely to have timeouts trying a nonworking v6
address hold up connecting to a working v4 address.  On other systems,
the likelihood of trying broken v6 automatic tunnels before working v4
goes way up.

The fraction of a percent of users (1 in 1000) today having that
problem with preference for broken IPv6 causes google to go to the
extreme step of negotiating good IPv6 access with each end network
before publishing AAAA records for important domains like
www.youtube.com and www.google.com to that end network.  This "DNS
whitelisting" approach does not scale and is not for most of us.

A relatively recent proposal is to change client applications to try
parallel lookup/connects on all addresses.  This "happy eyeballs"
approach, as the v6ops working group refers to it, suggests firing off
attempts to connect and handshake with all of the addresses returned
for the destination hostname, possibly slightly staggered to avoid
completely disrespecting any wisdom in the address selection (ordering
of the list from getaddrinfo).

Mark Andrews has posted example "happy eyeballs" client TCP connection
code for both nonblocking and threaded approaches:

http://www.isc.org/community/blog/201101/how-to-connect-to-a-multi-homed-server-over-tcp

It has been suggested you want to race not only connect(), but also
any subsequent handshaking you can do to verify the connection is
actually working, before aborting losing simultaneous attempts.

Using libevent, it's even easier than in Mark's examples to issue
parallel attempts, at least for UDP.  I'm guessing libevent supports
nonblocking connect() for TCP?

Cheers,
Dave Hart

Cheers,
Dave Hart
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.