fix(peer): record listener addresses during handshakes
Peers discovered over mDNS could still attribute later library sync traffic to temporary QUIC source ports. In a real GUI LAN run this made Host B try to push its library to Host A's outbound port instead of Host A's advertised listener, so Host A discovered the peer but never saw its games. Carry the stable listener address in Hello and HelloAck, and key library sync messages by peer_id instead of inferring identity from the transport source address. The handshake path now explicitly refreshes an empty peer library from the known listener address, matching the reliability of the direct-connect CLI path without overwriting richer snapshot state when it already arrived. This changes the current wire protocol, so PROTOCOL_VERSION is bumped to 3 and all peers must be rebuilt together. The architecture note now documents that listener addresses come from mDNS or Hello/HelloAck, never from ephemeral QUIC source ports. Test Plan: - just fmt - just test - just clippy - just build - git diff --check Refs: Local Linux/Win11 GUI LAN test logs from 2026-05-18.
This commit is contained in:
@@ -27,7 +27,11 @@ chunked file transfers.
|
||||
When a peer is discovered:
|
||||
|
||||
1. Connect and send `Hello { peer_id, proto_ver, library_rev, library_digest, features }`.
|
||||
2. Receive `HelloAck { peer_id, proto_ver, library_rev, library_digest, features }`.
|
||||
`Hello` also carries the sender's advertised `listen_addr`; the QUIC source
|
||||
port is only a temporary transport port and must not be recorded as the
|
||||
peer's listener.
|
||||
2. Receive `HelloAck { peer_id, proto_ver, listen_addr, library_rev,
|
||||
library_digest, features }`.
|
||||
3. If the remote `peer_id` is already known but the address changed, update it.
|
||||
4. If protocol versions are incompatible, drop the peer (and keep mDNS watching).
|
||||
5. If library digests match, do nothing else.
|
||||
@@ -51,12 +55,12 @@ When a peer is discovered:
|
||||
|
||||
### Summary and snapshot
|
||||
|
||||
- `LibrarySummary { library_rev, library_digest, game_count }`
|
||||
- `LibrarySnapshot { library_rev, games: Vec<GameSummary> }`
|
||||
- `LibrarySummary { peer_id, summary: { library_rev, library_digest, game_count } }`
|
||||
- `LibrarySnapshot { peer_id, snapshot: { library_rev, games: Vec<GameSummary> } }`
|
||||
|
||||
### Delta updates
|
||||
|
||||
- `LibraryDelta { from_rev, to_rev, added, updated, removed }`
|
||||
- `LibraryDelta { peer_id, delta: { from_rev, to_rev, added, updated, removed } }`
|
||||
- `removed` is a list of game IDs.
|
||||
- Deltas are idempotent; ignore if `to_rev` <= known rev.
|
||||
|
||||
@@ -142,6 +146,8 @@ Most scans become O(number of game dirs), with full recursion only when needed.
|
||||
## Fault tolerance rules
|
||||
|
||||
- Every peer is keyed by `peer_id`, not by IP address.
|
||||
- Peer addresses are listener addresses from mDNS or `Hello`/`HelloAck`, never
|
||||
ephemeral QUIC source ports.
|
||||
- `library_rev` is monotonic and guards against out-of-order updates.
|
||||
- Any mismatch or missing delta falls back to `LibrarySnapshot`.
|
||||
- Loss of goodbye is harmless; stale timeout is authoritative.
|
||||
@@ -153,8 +159,10 @@ Most scans become O(number of game dirs), with full recursion only when needed.
|
||||
`LibraryDelta`, and optional `Goodbye` messages.
|
||||
- Thread `peer_id`, `library_rev`, and `manifest_hash` through all
|
||||
library and manifest-bearing types.
|
||||
- Make `HelloAck` carry the remote `library_rev` and `manifest_hash`
|
||||
so the client can immediately select `LibraryDelta` vs `LibrarySnapshot`.
|
||||
- Make `Hello` and `HelloAck` carry the sender's `listen_addr`,
|
||||
`library_rev`, and `library_digest` so both sides can record stable
|
||||
listener addresses and immediately select `LibraryDelta` vs
|
||||
`LibrarySnapshot`.
|
||||
2. Peer identity:
|
||||
- Persist a stable `peer_id` (UUID) in the peer config and inject it into
|
||||
`PeerInfo` and `PeerGameDB` at startup.
|
||||
|
||||
Reference in New Issue
Block a user