Repository navigation
feat(webrtc): true ICE-Lite controlled agent for the WebRTC-Direct listener #1512
Description
Activity
yashksaini-coder commented
on Sep 8, 2026 ContributorAuthorMore actionsFindings — how other implementations handle the listener's ICE-Lite role.
The spec requires it — webrtc-direct.md: "B acts as an ICE Lite agent … binds to a UDP port waiting for incoming STUN and SCTP packets and multiplexes based on source IP and source port."
Every reference implementation gets Lite as a native flag in its ICE library:
- go-libp2p (pion):
settingEngine.SetLite(true)(p2p/transport/webrtc/listener.go:208, v0.49). Its whole listener setup otherwise matches ours — server DTLS role,SetICECredentials(serverUfrag, serverUfrag), UDP mux, loopback candidate, disable fingerprint verify. The one line we can't mirror isSetLite(true). - rust-libp2p (webrtc-rs):
SettingEngine::set_lite. - js-libp2p: the browser client is full-ICE by construction; node side via libdatachannel.
What pion's Lite actually does: "Lite agents do not perform connectivity checks and only provide host candidates" — host-only, respond-only (never initiate checks), always controlled, completes on the controlling peer's
USE-CANDIDATE.Where py-libp2p stands. Our listener already meets 3 of the 4: a single injected host candidate, always controlled (
ice_controlling=False), and completion on the dialer's nomination. The only gap is respond-only — we still send our own connectivity checks — because aioice has no local Lite mode, onlyremote_is_lite.Conclusion. True ICE-Lite is a library primitive everywhere else; the clean fix is to add an
ice_litemode to aioice (mirroring pion'sLite). Re-implementing it as a per-connection override of aioice internals in py-libp2p would be fragile and pinned to aioice 0.10.x. The current full-controlled agent interoperates (the dialer nominates) and is robust after #1495, so it stands as a documented interim. Leaving this open as a known ceiling; the eventual fix is upstream in aioice.- go-libp2p (pion):
yashksaini-coder commented
on Sep 10, 2026 ContributorAuthorMore actionsUpdate: implemented in-repo after all → #1532 (closes this).
Revisiting my earlier "clean fix is upstream aioice" note: a contained in-repo override turned out to be clean and interop-verified. aioice's
check_startis its sole sender of connectivity-check requests, so replacing it on the muxed listener connection with a respond-only version (mark the pair valid, complete on the dialer'sUSE-CANDIDATE) makes the agent genuinely Lite without touching aioice. Also pinswitch_roleso it stays controlled per RFC 8445 §6.1.1. Validated against go-libp2p v0.49 (both directions, v1+v2) — 0 outbound connectivity checks from the listener, all combos green. Upstreaming a realice_liteinto aioice is still the cleaner long-term home, but this unblocks the #1437 track now.- added a commit that references this issue
on Oct 2, 2026
Follow-up on #1437. The WebRTC-Direct listener currently runs a full
aioiceagent in the controlled role, not a true ICE-Lite agent. It interoperates because the remote dialer is full ICE and nominates, but it is not spec-Lite.A Lite agent (RFC 8445 §2.1 / the WebRTC-Direct server role) should:
Today aioice has no lite mode, so the full controlled-agent machinery runs: it sends its own checks and can discover peer-reflexive candidates. Making it truly Lite means either:
ice_litemode into aioice — cleaner and reusable, but out-of-repo and slower.Plan: scope option 1 first behind the existing muxed-connection setup and verify against the go-libp2p interop suite (both directions, v1+v2). Refs #1437.