From 8288714853952aca6b3511268b9d772f1b7f489f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 4 Sep 2026 13:44:12 +0200 Subject: fix(node): make ice_interfaces match adapters on Windows (W9) `ice_interfaces` compared the operator's entry against ifaddr's `adapter.name` only -- the kernel name on Linux (`wlp3s0f0`), but the adapter GUID on Windows (`{846EE342-...}`). A setting written on Linux, or copied into a Windows node's node.toml, matched no adapter at all. The failure was silent and total rather than partial: aioice binds one socket per host address, so an empty list means no sockets, no host candidates, and an SDP offering only a reflexive address. The settings field is free text with no picker, and on Windows the operator sees neither the GUID nor the description -- `ipconfig` shows the connection name -- so an entry now matches the adapter name, the device description, or one of the adapter's own IPv4 addresses, case-insensitively. An address is the one identifier visible on every platform. A filter that matches nothing now falls back to the unfiltered list with a warning. Losing the 5 s timeout saving is a regression; being silently unconnectable is a defect. Also fixes IPv4/IPv6 discrimination in the same loop: the two were told apart by falling through to an `elif` that index-probed `ip.ip[0]` and `ip.ip[2]`, which on an IPv4 str yields characters that compared unequal by luck rather than by design. Now discriminated by isinstance. WINDOWS-PORT.md claimed Transport had "no platform dependency"; it does. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DtfG7z6wHWj8RKHCvxQtY1 --- docs/WINDOWS-PORT.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/WINDOWS-PORT.md b/docs/WINDOWS-PORT.md index 239dbd1..ceba2b8 100644 --- a/docs/WINDOWS-PORT.md +++ b/docs/WINDOWS-PORT.md @@ -27,7 +27,7 @@ it matters most: | `meshbay_common/` (all other modules) | **Ready** | Crypto, protocol, keyderive — no OS dependency | | `roots.py` | **Ready** | Uses `fold()`, `portable_name_problem()`, `as_posix()` for virtual paths, Windows drive examples in docstrings | | `indexer/indexer.py` | **Ready** | `as_posix()` for index paths, `long_path()` for file I/O, reconciliation loop for dropped `ReadDirectoryChangesW` events | -| Transport (WebRTC, QUIC, MNP) | **Ready** | asyncio + aiortc, no platform dependency | +| Transport (WebRTC, QUIC, MNP) | **Ready** | asyncio + aiortc. One platform dependency: `ice_filter.py` matches adapters by `ifaddr` name, which is a kernel name on Linux and a GUID on Windows — see W9 | | Roster, bundle store, audit, chat store | **Ready** | SQLite + pathlib throughout | | `test_paths.py` | **Ready** | Case folding, NFC, reserved names, reserved characters, trailing dot/space — already covers Windows filesystem rules | | Electron `preload.js` | **Ready** | Pure IPC bridge, no platform code | @@ -394,6 +394,30 @@ when `sys.platform == "win32"`. **Estimated scope:** ~20 lines, cosmetic. +### 5.8 ICE interface naming (W9) + +**Scope:** `transport/ice_filter.py` + +`ice_interfaces` restricts ICE gathering to named adapters. The filter compared +the operator's entry against `ifaddr`'s `adapter.name` only — the kernel name +on Linux (`wlp3s0f0`), but the adapter **GUID** on Windows +(`{846EE342-7039-11DE-9D20-806E6F6E6963}`). A setting written on Linux, or +copied into a Windows guest's `node.toml`, therefore matched no adapter at all. + +The failure was silent and total rather than partial: aioice binds one socket +per host address, so an empty list means no sockets, no host candidates, and an +SDP offering only a server-reflexive address. Behind two NATs — a VM on a +libvirt NAT inside a LAN — that address is unreachable for a peer on the +intermediate LAN, so ICE never completes and the symptom reads as a network +fault, not a config one. + +An entry now matches the adapter name, the device description +(`adapter.nice_name`, which is what Windows populates), or one of the adapter's +own IPv4 addresses — the settings field is free text with no picker, so +operators write whichever identifier they can see. A filter that matches +nothing falls back to the unfiltered list with a warning: losing the 5 s +timeout saving is a regression, being unconnectable is a defect. + --- ## 6. Execution order @@ -405,6 +429,7 @@ W5 File permissions ✅ done W7 CLI messages ✅ done W6 ffmpeg discovery ✅ done W8 test suite green on win32 ✅ done (encoding sweep + skipif; 784 pass) +W9 ICE interface naming ✅ done (name/description/IP match + fail-open) ──── milestone: daemon runs on Windows ✅ (verified end to end) ──── W3 Daemon lifecycle ✅ done — Startup-folder .vbs (Task Scheduler needs admin) ──── milestone: daemon starts/stops on Windows ✅ ──── @@ -417,6 +442,7 @@ W4 Packaging ✅ built — one per-user NSIS installer, client ``` W1–W2–W5–W6–W7–W8 shipped as a run of mechanical commits, testable on Linux. +W9 came out of a live guest that could not connect at all. W3 and W4 were the real work. --- -- cgit v1.2.3