Skip to content

Android↔iOS direct-dial falls back to relay (no direct path established) #359

Description

@momics

Summary

On-device interop testing shows that the Android ↔ iOS peer pair cannot establish a direct QUIC path and falls back to the relay, even though both peers now advertise all their routable direct addresses (#348). The request still completes (relay returns HTTP 200), so this is a connectivity/hole-punching robustness gap rather than a functional outage. Every other pair in the matrix (desktop↔iOS, desktop↔Android, and — in run-3 — Android→desktop) reaches transport=direct.

Evidence

From two consecutive on-device passes (both phones + desktop node on one LAN), the direct-dial-fetch case (tests/interop/suite.mjs, which passes all advertised addresses via directAddrs so iroh races every candidate):

  • run-2 android→ios: HTTP 200 via 10.12.222.17:64939 — transport=relay (reached over RELAY, not direct ✗)
  • run-3 android→ios: HTTP 200 via 10.12.222.17:54534 — transport=relay (reached over RELAY, not direct ✗)

Note 10.12.222.17 is iOS's VPN/CG-NAT interface; iOS also advertises a real LAN 192.168.x address (post-#348), yet the pair still lands on relay. run-3 also showed android→desktop reaching direct, so the failure is specific to the Android↔iOS pair, not Android-as-client in general.

Impact

  • Android↔iOS traffic always traverses the relay: higher latency, relay bandwidth dependency, and it defeats the core P2P-direct value proposition for that pair.
  • Not a hard failure — relay fallback delivers correct responses (200, uncorrupted body).
  • Likely environmental (interface enumeration / NAT / candidate exchange between the two mobile stacks), so it needs investigation before we know whether it is fixable in our layer or is an iroh/network characteristic.

Remediation

  1. Capture iroh path/candidate diagnostics on both peers during an Android→iOS dial (which candidate pairs are tried, which time out) via peerStats() / connection-path events.
  2. Confirm both peers actually exchange the LAN candidate (TXT carries it; verify the dialer imports it and iroh attempts it) vs. it being gathered-but-not-punched.
  3. Determine whether the block is a firewall/AP client-isolation issue on the test LAN, an iOS/Android interface-binding limitation, or a real gap in our address plumbing.
  4. If environmental, document the finding and downgrade; if a plumbing gap, fix and add a device-verified regression note.

Acceptance criteria

  1. Root cause identified: environmental vs. product (address gather/import/punch).
  2. If fixable in our layer, Android→iOS and iOS→Android direct-dial-fetch report transport=direct on a clean LAN, device-verified.
  3. If environmental, the constraint is documented (e.g. in the device-pass runbook / protocol notes) and the case's expectation is adjusted so it no longer reads as an unexplained regression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium prioritybugSomething isn't workingconnectivityPeer discovery and connection

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions