diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-01 01:13:43 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-01 01:13:43 +0200 |
| commit | b3b48a43a33f936be18a3daa22d307c144b60e22 (patch) | |
| tree | bf7dde66f00490023e028c5a23e2ef353b16e4fd /packages/meshbay-node/src/meshbay_node/ops.py | |
| parent | fe30860c58e0f1b1efd457ff5eb5146d1e592da0 (diff) | |
| download | meshbay-b3b48a43a33f936be18a3daa22d307c144b60e22.tar.gz | |
fix(node): make WebRTC STUN fallback actually use every configured server
aiortc's connection_kwargs() keeps only the first STUN URI from
RTCConfiguration.iceServers ("only a single STUN server is supported"),
and aioice.ice.Connection has a single stun_server field. So the node's
four default STUN servers -- and anything added on the Node page or with
`meshbay-node stun add` -- collapsed to stun:stun.l.google.com:19302. When
that one server was slow or unreachable from the node, ICE gathering
(get_component_candidates, timeout=5) burned its full 5 s with no
server-reflexive candidate, adding seconds to every browser connection.
The multi-server fallback of draft-v6 s2.12 was configuration only.
transport/stun_multi patches aioice.ice.server_reflexive_candidate (same
monkey-patch technique ice_filter.py uses on get_host_addresses) so a
single ICE gather races the STUN binding request against every configured
server on the one bound socket and takes the first answer. One reachable
server anywhere in the list now yields a reflexive candidate in one RTT.
- daemon: install_stun_multi() alongside install_ice_filter()
- ops.set_node_settings: push the list to stun_multi.set_servers() so the
CLI / Node-page hot-swap takes effect without a restart
- webrtc_server.handle_offer: log ICE gather time and srflx count
- test_stun_multi.py: fan-out, first-answer-wins, all-fail, empty-list
fallback, DNS failure
Verified end to end with a real RTCPeerConnection: with a black-hole STUN
server first in the list, gathering still completes in ~0.07 s with full
srflx candidates (previously a 5 s stall).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSsQhfxEAhwi4nqc4hASmq
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ops.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ops.py | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py index cd5dc32..34a569f 100644 --- a/packages/meshbay-node/src/meshbay_node/ops.py +++ b/packages/meshbay-node/src/meshbay_node/ops.py @@ -877,6 +877,8 @@ async def set_node_settings(state: dict, settings: dict) -> dict: webrtc = state.get("webrtc") if webrtc and hasattr(webrtc, '_stun'): webrtc._stun = updated["stun_servers"] + from meshbay_node.transport.stun_multi import set_servers as _set_stun + _set_stun(updated["stun_servers"]) if "ice_interfaces" in updated: from meshbay_node.transport.ice_filter import install as install_ice_filter install_ice_filter(updated["ice_interfaces"] or None) |