Affected protocols
- Identify request (
/ipfs/id/1.0.0)
- AutoNAT v1 request/response (
/libp2p/autonat/1.0.0)
- Potentially other one-shot handlers dispatched by the Switch
These exchanges complete after one response and must finish the Yamux stream lifecycle rather than leave a permanent half-open stream.
Current state
requestIdentify reads the framed response and returns without closing its local stream side. The responder does send FIN, leaving the initiator handle in a remote-half-closed state until it sends its own FIN.
AutoNAT's responder writes its response without closing, and requestAutoNAT also returns without closing.
Switch.Listen.dispatchStream releases the resource-manager stream reservation when a handler returns but does not close the actual stream. Thus accounting can say the stream was released while the Yamux session still retains it.
Scope
- Define clear stream ownership for
StreamHandler: either every one-shot handler closes its stream, or dispatch provides a safe close-on-return policy with an explicit escape hatch for long-lived/handed-off streams.
- Close Identify initiator streams on success, negotiation rejection, decoding failure, and exceptions.
- Close both AutoNAT sides after their one-response exchange on all exit paths.
- Ensure close is idempotent and does not discard a response before it is flushed.
- Keep long-lived handlers (DHT, Ping sessions, relayed streams, GossipSub) working under the chosen ownership model.
- Align resource-manager release with actual stream termination.
Acceptance tests
- Repeated Identify requests return the Yamux stream map and resource usage to baseline.
- Repeated AutoNAT requests do the same on both peers.
- Decode/negotiation/error paths close or reset the stream.
- A handler that explicitly hands off a long-lived stream is not prematurely closed.
- Stream reservation counts match live Yamux streams after handler completion.
Affected protocols
/ipfs/id/1.0.0)/libp2p/autonat/1.0.0)These exchanges complete after one response and must finish the Yamux stream lifecycle rather than leave a permanent half-open stream.
Current state
requestIdentifyreads the framed response and returns without closing its local stream side. The responder does send FIN, leaving the initiator handle in a remote-half-closed state until it sends its own FIN.AutoNAT's responder writes its response without closing, and
requestAutoNATalso returns without closing.Switch.Listen.dispatchStreamreleases the resource-manager stream reservation when a handler returns but does not close the actual stream. Thus accounting can say the stream was released while the Yamux session still retains it.Scope
StreamHandler: either every one-shot handler closes its stream, or dispatch provides a safe close-on-return policy with an explicit escape hatch for long-lived/handed-off streams.Acceptance tests