don't use net.Errors for streams map error (#5060)

This commit is contained in:
Marten Seemann
2025-04-19 22:16:47 +08:00
committed by GitHub
parent 9e1afd4fb4
commit a1aa369464
4 changed files with 14 additions and 43 deletions

View File

@@ -2,9 +2,7 @@ package quic
import (
"context"
"errors"
"fmt"
"net"
"sync"
"github.com/quic-go/quic-go/internal/flowcontrol"
@@ -34,19 +32,6 @@ func convertStreamError(err error, stype protocol.StreamType, pers protocol.Pers
return fmt.Errorf(strError.Error(), ids...)
}
type streamOpenErr struct{ error }
var _ net.Error = &streamOpenErr{}
func (streamOpenErr) Timeout() bool { return false }
func (e streamOpenErr) Unwrap() error { return e.error }
func (e streamOpenErr) Temporary() bool {
// In older versions of quic-go, the stream limit error was documented to be a net.Error.Temporary.
// This function was since deprecated, but we keep the existing behavior.
return errors.Is(e, &StreamLimitReachedError{})
}
// StreamLimitReachedError is returned from Connection.OpenStream and Connection.OpenUniStream
// when it is not possible to open a new stream because the number of opens streams reached
// the peer's stream limit.

View File

@@ -58,7 +58,7 @@ func (m *outgoingStreamsMap[T]) OpenStream() (T, error) {
// if there are OpenStreamSync calls waiting, return an error here
if len(m.openQueue) > 0 || m.nextStream > m.maxStream {
m.maybeSendBlockedFrame()
return *new(T), streamOpenErr{&StreamLimitReachedError{}}
return *new(T), &StreamLimitReachedError{}
}
return m.openStream(), nil
}

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"math/rand/v2"
"net"
"testing"
"time"
@@ -59,19 +58,6 @@ func TestStreamsMapOutgoingOpenAndDelete(t *testing.T) {
require.Nil(t, str)
}
func checkTooManyStreamsError(t *testing.T, err error) {
t.Helper()
require.Error(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
nerr, ok := err.(net.Error)
require.True(t, ok)
require.False(t, nerr.Timeout())
//nolint:staticcheck // SA1019
// In older versions of quic-go, the stream limit error was documented to be a net.Error.Temporary.
// This function was since deprecated, but we keep the existing behavior.
require.True(t, nerr.Temporary())
}
func TestStreamsMapOutgoingLimits(t *testing.T) {
m := newOutgoingStreamsMap(
protocol.StreamTypeBidi,
@@ -86,7 +72,7 @@ func TestStreamsMapOutgoingLimits(t *testing.T) {
// We've now reached the limit. OpenStream returns an error
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
// OpenStreamSync with a canceled context will return an error immediately
ctx, cancel := context.WithCancel(context.Background())
@@ -110,7 +96,7 @@ func TestStreamsMapOutgoingLimits(t *testing.T) {
}
// OpenStream still returns an error
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
// cancelling the context unblocks OpenStreamSync
cancel()
select {
@@ -240,7 +226,7 @@ func TestStreamsMapOutgoingBlockedFrames(t *testing.T) {
require.Empty(t, frameQueue)
_, err := m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
require.Equal(t, []wire.Frame{
&wire.StreamsBlockedFrame{Type: protocol.StreamTypeBidi, StreamLimit: 3},
}, frameQueue)
@@ -248,7 +234,7 @@ func TestStreamsMapOutgoingBlockedFrames(t *testing.T) {
// only a single STREAMS_BLOCKED frame is queued per offset
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
require.Empty(t, frameQueue)
errChan := make(chan error, 3)
@@ -342,7 +328,7 @@ func TestStreamsMapOutgoingRandomizedOpenStreamSync(t *testing.T) {
str, err := m.OpenStream()
if limit <= n {
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
} else {
require.NoError(t, err)
require.Equal(t, protocol.StreamNum(n+1), str.num)

View File

@@ -275,20 +275,20 @@ func testStreamsMapStreamLimits(t *testing.T, perspective protocol.Perspective)
// increase via transport parameters
_, err := m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
m.UpdateLimits(&wire.TransportParameters{MaxBidiStreamNum: 1})
_, err = m.OpenStream()
require.NoError(t, err)
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
_, err = m.OpenUniStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
m.UpdateLimits(&wire.TransportParameters{MaxUniStreamNum: 1})
_, err = m.OpenUniStream()
require.NoError(t, err)
_, err = m.OpenUniStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
// increase via MAX_STREAMS frames
m.HandleMaxStreamsFrame(&wire.MaxStreamsFrame{
@@ -298,7 +298,7 @@ func testStreamsMapStreamLimits(t *testing.T, perspective protocol.Perspective)
_, err = m.OpenStream()
require.NoError(t, err)
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
m.HandleMaxStreamsFrame(&wire.MaxStreamsFrame{
Type: protocol.StreamTypeUni,
@@ -307,12 +307,12 @@ func testStreamsMapStreamLimits(t *testing.T, perspective protocol.Perspective)
_, err = m.OpenUniStream()
require.NoError(t, err)
_, err = m.OpenUniStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
// decrease via transport parameters
m.UpdateLimits(&wire.TransportParameters{MaxBidiStreamNum: 0})
_, err = m.OpenStream()
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
}
func TestStreamsMapClosing(t *testing.T) {
@@ -411,5 +411,5 @@ func TestStreamsMap0RTTRejection(t *testing.T) {
m.UseResetMaps()
_, err = m.OpenStream()
require.Error(t, err)
checkTooManyStreamsError(t, err)
require.ErrorIs(t, err, &StreamLimitReachedError{})
}