Skip to content

Try every resolved address when connecting a TCP socket - #2214

Merged
pedroSG94 merged 1 commit into
pedroSG94:masterfrom
x270880x:fix/connect-all-addresses
Oct 17, 2026
Merged

pedroSG94 merged 1 commit into
pedroSG94:masterfrom
x270880x:fix/connect-all-addresses

Conversation

@x270880x

Copy link
Copy Markdown
Contributor

Problem

TcpStreamSocketJava.onConnectSocket connects to InetSocketAddress(host, port), which uses only the first address the host resolves to. On Android, when the device has an IPv6 address, dual-stack ingest hosts usually resolve IPv6 first. If IPv6 is assigned on that network but doesn't work, the connect is refused or times out and the stream doesn't start, even though the same server answers over IPv4. Browsers and OkHttp move on to the next address, so for the user "the internet works" but streaming doesn't.

We saw this pattern in our app's reports: one device failed to connect to both YouTube and Twitch ingest over IPv6 (isConnected failed: ECONNREFUSED), and those connects were never tried over IPv4. The report can't tell us whether IPv4 would have worked on that network, so please treat this as a robustness change, not a proven fix for that case.

Change

  • Resolve every address of the host and try them in the order the system returns them, within the original timeout. Each attempt gets an equal share of the time that is left, so a host with a single address behaves exactly as before.
  • Only the TCP connect moves on to the next address. A TLS handshake error is reported as it is.
  • The host name is kept in the connected address (InetAddress.getByAddress(host, bytes)), so SNI and hostname verification work as before.
  • resolver is an internal property, only to make this testable.

Ktor sockets (SocketType.KTOR) are not changed here.

Testing

  • New JVM tests in common (TcpStreamSocketJavaTest): fallback from a failing first address to a working one, first address used when it works, host name kept, and an error when no address connects.
  • ./gradlew :common:testDebugUnitTest (102 tests) and ./gradlew :rtmp:testDebugUnitTest (59 tests) pass locally.
  • Not run on a device: we don't have a network with broken IPv6 to reproduce it.

🤖 Generated with Claude Code

TcpStreamSocketJava connected only to the first address the host
resolved to. On a network where IPv6 is assigned but broken, a host
with both IPv6 and IPv4 addresses resolves IPv6 first, that address
refuses or times out, and the stream fails although the server is
reachable over IPv4.

Now every resolved address is tried in the system order within the
original timeout (each one gets an equal share of the time left).
Only the TCP connect moves on to the next address; a TLS handshake
error is reported as it is. The host name is kept in the connected
address, so SNI and certificate checks are unchanged.
@pedroSG94
pedroSG94 merged commit 9427096 into pedroSG94:master Oct 17, 2026
1 check passed
@pedroSG94

Copy link
Copy Markdown
Owner

Thank you for the PR. Merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants