Find a paired machine again after either side changes network - #453
Merged
Merged
Conversation
hello_ok now carries the host's non-loopback, non-link-local interface addresses and its listening port, and hello_rejected carries the host_id, so a client can remember where else the paired machine answers and can tell its own machine's refusal from a stranger that now owns a stale address. local_addrs moves to discovery, shared by pairing codes and hello, and if-addrs becomes an unconditional dependency of tcode-remote (mdns-sd already pulls it on every target).
A pairing is bound to the machine identity, never to an address. PairedHost keeps a bounded, ordered list of candidate origins next to the one that last worked: origins that completed hello before, the addresses the machine reported in hello_ok, and LAN discovery hints. Older hosts.json records load unchanged; legacy multi-address records migrate their extra addresses to candidates. The native connection loop owns finding the machine again. The saved origin is tried alone first; once it fails to answer, or as soon as this device's interface addresses change, it races the candidates and probes derived from the device's own networks (hotspot and small-subnet gateways, every guest of a /28 hotspot it shares) with a five-second budget each. Every reply is judged by host_id: the first answer from the paired machine wins and is promoted and persisted, a different machine at any address is a plain miss, and only the paired machine's own token rejection ends the pairing. HTTPS pairings are never downgraded; the browser client keeps its page origin. The loop polls its interface set (2.5 s while reconnecting, 10 s while connected): a change cuts the backoff short with a reset delay, or probes a live socket so one left on a vanished interface is replaced within seconds. The store's per-attempt mDNS browse now only feeds hints to the transport (Wake::Candidates) instead of swapping the origin itself. Closes #409.
Describe candidate origins in hosts.json, the identity-verified racing and interface probes, hotspot behaviour, the network-change wake, and that HTTPS pairings are never downgraded. DESIGN.md notes that finding the machine at another address is silent in the Reconnecting banner.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #409.
Behaviour
A pairing is bound to the machine identity (
host_id), not to an address. When the saved origin stops answering, or this device's interface addresses change, a native client races every origin it knows for the same machine and resumes the same session without re-pairing or manual address entry.PairedHostgains a bounded, orderedcandidateslist (max 16): origins that completed hello before, the addresses the machine reports inhello_ok, and mDNS hints. Olderhosts.jsonrecords (one origin, or legacyaddrs+port) still load; the one-origin form re-serializes unchanged.hello_oknow carriesaddrsandport;hello_rejectedcarrieshost_id. Ahello_okor token rejection from a different machine at a stale address counts as unreachable, never as "Pair again". Only the paired machine (or an older host at the saved origin that does not name itself) can end the pairing..1of private networks up to /24, and every guest of a private /28 or smaller. Only for plainhttporigins;httpspairings are never downgraded. The browser client keeps its fixed page origin.addr_autoservices on interface changes (ip-check timer every 5 s), so the beacon needs no change beyond the hello fields. The listener already binds all interfaces.The transport is now the single owner of "find the host again"; the UI store only forwards mDNS hints through
Wake::Candidates(iOS can drive Bonjour only from the UI thread).refresh_originis replaced bydiscover_origins.Tests
hosts.jsonfixtures load and migrate; promotion and bounded candidates.hello_verdictagainst literalhello_ok/hello_rejectedshapes: mismatch is non-terminal, missinghost_idprimary-vs-candidate,addrsfiltering.Reconnecting, the answering candidate is promoted, token and stamp untouched; literalhello_ok/hello_rejectedJSON asserted.Checks run
cargo fmt --all --check,cargo clippy --workspace --all-targets --locked -- -D warnings,cargo build --workspace --locked,cargo test --workspace --locked(all green),cargo machete, iOS sim / wasm32 / Android arm64cargo checkwith-D warnings.Live check: headless host paired on port 47500, then restarted on 47501 with the same data dir; the client hit connection-refused on the saved origin, picked up the mDNS hint, promoted the new origin in
hosts.jsonand reconnected with the original token (one device record on the host, no re-pair). Not exercised live: real phone hotspots and interface aliasing (covered by pure-function tests).Known gaps
100.64/10) and other non-private networks get no gateway probe by design.stamp_connected(UI) both load→modify→savehosts.json; they run sequentially in practice but there is no file lock.