Happy Eyeballs in Chromium for Dual-Stack Connections
This article explains how the Chromium web browser uses the Happy Eyeballs algorithm to connect to dual-stack hosts supporting both IPv6 and IPv4. It covers the entire connection racing process, starting from asynchronous DNS resolution and IPv6 prioritization, moving through the fallback timer mechanism, and concluding with how Chromium selects the winning connection and terminates the redundant attempt to ensure fast, seamless browsing.
1. Asynchronous DNS Resolution
When you navigate to a website, Chromium needs the server's IP
address. For a dual-stack host, the browser sends two DNS queries
simultaneously: an AAAA request for IPv6 addresses and an
A request for IPv4 addresses.
Because Chromium prioritizes IPv6, it acts immediately if the
AAAA record arrives first. If the IPv4 A
record arrives first, Chromium starts a brief 50-millisecond timer. This
gives the IPv6 response a slight head start to arrive before the browser
defaults to starting the connection with IPv4.
2. Address Sorting and IPv6 Initiation
Once the DNS responses are received, Chromium compiles a list of available IP addresses. It interleaves the addresses by family, placing the preferred IPv6 address at the very top of the list, followed by the primary IPv4 address.
Chromium then initiates the first connection attempt by sending a TCP
SYN packet (or initiating a QUIC handshake) to the first
IPv6 address on the list.
3. The 250-Millisecond Racing Timer
At the exact moment Chromium initiates the IPv6 connection, it starts a "connection attempt delay" timer set to 250 milliseconds.
Historically, broken IPv6 routing would cause browsers to hang for several seconds waiting for a timeout before trying IPv4. The 250ms timer solves this by defining the maximum amount of time Chromium is willing to wait for IPv6 to respond before taking backup action.
4. Starting the Race (IPv4 Fallback)
If the IPv6 connection succeeds before the 250ms timer expires, the process ends, and the browser loads the webpage over IPv6.
However, if the 250ms timer expires and the IPv6 handshake is still incomplete—or if the IPv6 attempt fails immediately due to a network error—Chromium does not cancel the IPv6 attempt. Instead, it leaves the IPv6 attempt running in the background and immediately fires off a parallel connection attempt to the first IPv4 address on its list. At this point, the IPv6 and IPv4 connections are actively racing each other.
5. Winning the Connection Race
Chromium monitors both open sockets. The first connection to
successfully complete its handshake (such as returning a TCP
SYN-ACK packet) is declared the winner. Chromium
immediately binds this winning socket to the HTTP request and begins
transferring data for the webpage.
6. Teardown and Caching
The millisecond a winner is declared, Chromium aborts the losing connection attempt. If IPv4 won the race, the still-pending IPv6 socket is forcibly closed, preventing wasted network resources and half-open connections on the server.
Finally, Chromium caches the result of the race. For subsequent connections to the same host in the near future, Chromium will remember which protocol won and use it directly, bypassing the delay until the cache expires or the network state changes.