fix(basic_host): set read deadline before multistream Close to prevent blocking

streamWrapper.Close() can block indefinitely when the remote peer is slow
or unresponsive during the multistream-select handshake completion.

The lazy multistream protocol negotiation defers reading the handshake
response until Close() is called. If the remote peer doesn't respond,
the read blocks forever, causing goroutine leaks.

This is particularly problematic for bitswap servers where taskWorkers
can get stuck trying to close streams after sending blocks.

The fix sets a read deadline (using DefaultNegotiationTimeout) before
calling the multistream Close(), ensuring the operation will time out
rather than block indefinitely.

Related: https://github.com/multiformats/go-multistream/issues/47
Related: https://github.com/multiformats/go-multistream/pull/48
This commit is contained in:
Marcin Rataj
2026-01-07 01:19:16 +01:00
committed by Marco Munizaga
parent 479b24baab
commit bcc2bf1866
2 changed files with 86 additions and 0 deletions
+5
View File
@@ -683,6 +683,11 @@ func (s *streamWrapper) Write(b []byte) (int, error) {
}
func (s *streamWrapper) Close() error {
// Set a read deadline to prevent Close() from blocking indefinitely
// waiting for the multistream-select handshake to complete.
// This can happen when the remote peer is slow or unresponsive.
// See: https://github.com/multiformats/go-multistream/issues/47
_ = s.Stream.SetReadDeadline(time.Now().Add(DefaultNegotiationTimeout))
return s.rw.Close()
}