mirror of
https://github.com/go-gost/x.git
synced 2026-10-19 08:15:33 +00:00
A p2p dial's stream survives the peer session under it being rebuilt, so the link can go silently dead: the far side re-creates its session while this side's stream becomes a zombie — writes succeed into the void and nothing reports an error. firstInboundTimeout was a one-shot, cleared by the first inbound byte and never re-armed, so such a dial stayed "running" forever: on 2026-10-17 an Android spoke sat in a two-way blackhole for 17 minutes after the hub killed and rebuilt its relay session alone (derp peer-gone kill), while both ends reported the path up; only a manual entrypoint restart healed it. The registration refresh is echoed by the hub while the route to this device is real, so silence is measurable. A p2p dial now re-arms the read deadline to p2pInboundTimeout on every inbound byte; when it expires the dial ends and the caller redials, which re-registers and heals a hub-side rebuild — the same recovery a manual restart performs (observed as "peer relay session up … client=true"). Socket dials keep the one-shot semantics: their transport reports the far side gone by itself.