fix datagram support detection (#3511)

* fix: datagram support detection

- treat zero MaxDatagramFrameSize as unsupported.
- avoid send corresponding transport parameters when support is disabled
- report error when calling Send/ReceiveMessage and support is disabled

see https://github.com/lucas-clemente/quic-go/issues/3505

* patch: always initiate datagram

* fix: remove useless nil check
This commit is contained in:
KevinZønda
2022-08-22 11:02:40 +01:00
committed by GitHub
parent 509616cbea
commit a90135751b
2 changed files with 80 additions and 19 deletions

View File

@@ -316,6 +316,8 @@ var newConnection = func(
}
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
if s.tracer != nil {
s.tracer.SentTransportParameters(params)
@@ -441,6 +443,8 @@ var newClientConnection = func(
}
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
if s.tracer != nil {
s.tracer.SentTransportParameters(params)
@@ -535,9 +539,7 @@ func (s *connection) preSetup() {
s.creationTime = now
s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.connFlowController, s.framer.QueueControlFrame)
if s.config.EnableDatagrams {
s.datagramQueue = newDatagramQueue(s.scheduleSending, s.logger)
}
s.datagramQueue = newDatagramQueue(s.scheduleSending, s.logger)
}
// run the connection main loop
@@ -727,7 +729,7 @@ func (s *connection) Context() context.Context {
}
func (s *connection) supportsDatagrams() bool {
return s.peerParams.MaxDatagramFrameSize != protocol.InvalidByteCount
return s.peerParams.MaxDatagramFrameSize > 0
}
func (s *connection) ConnectionState() ConnectionState {
@@ -1977,6 +1979,10 @@ func (s *connection) onStreamCompleted(id protocol.StreamID) {
}
func (s *connection) SendMessage(p []byte) error {
if !s.supportsDatagrams() {
return errors.New("datagram support disabled")
}
f := &wire.DatagramFrame{DataLenPresent: true}
if protocol.ByteCount(len(p)) > f.MaxDataLen(s.peerParams.MaxDatagramFrameSize, s.version) {
return errors.New("message too large")
@@ -1987,6 +1993,9 @@ func (s *connection) SendMessage(p []byte) error {
}
func (s *connection) ReceiveMessage() ([]byte, error) {
if !s.config.EnableDatagrams {
return nil, errors.New("datagram support disabled")
}
return s.datagramQueue.Receive()
}

View File

@@ -32,7 +32,7 @@ var _ = Describe("Datagram test", func() {
dropped, total int32
)
startServerAndProxy := func() {
startServerAndProxy := func(enableDatagram, expectDatagramSupport bool) {
addr, err := net.ResolveUDPAddr("udp", "localhost:0")
Expect(err).ToNot(HaveOccurred())
serverConn, err = net.ListenUDP("udp", addr)
@@ -41,30 +41,39 @@ var _ = Describe("Datagram test", func() {
serverConn,
getTLSConfig(),
getQuicConfig(&quic.Config{
EnableDatagrams: true,
EnableDatagrams: enableDatagram,
Versions: []protocol.VersionNumber{version},
}),
)
Expect(err).ToNot(HaveOccurred())
go func() {
defer GinkgoRecover()
conn, err := ln.Accept(context.Background())
Expect(err).ToNot(HaveOccurred())
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func(i int) {
defer GinkgoRecover()
defer wg.Done()
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(i))
Expect(conn.SendMessage(b)).To(Succeed())
}(i)
if expectDatagramSupport {
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
if enableDatagram {
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func(i int) {
defer GinkgoRecover()
defer wg.Done()
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(i))
Expect(conn.SendMessage(b)).To(Succeed())
}(i)
}
wg.Wait()
}
} else {
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
}
wg.Wait()
}()
serverPort := ln.Addr().(*net.UDPAddr).Port
proxy, err = quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
RemoteAddr: fmt.Sprintf("localhost:%d", serverPort),
@@ -100,7 +109,7 @@ var _ = Describe("Datagram test", func() {
})
It("sends datagrams", func() {
startServerAndProxy()
startServerAndProxy(true, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
@@ -137,6 +146,49 @@ var _ = Describe("Datagram test", func() {
BeNumerically("<", num),
))
})
It("server can disable datagram", func() {
startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
clientConn,
raddr,
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
getTLSClientConfig(),
getQuicConfig(&quic.Config{
EnableDatagrams: true,
Versions: []protocol.VersionNumber{version},
}),
)
Expect(err).ToNot(HaveOccurred())
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
conn.CloseWithError(0, "")
<-time.After(10 * time.Millisecond)
})
It("client can disable datagram", func() {
startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
clientConn,
raddr,
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
getTLSClientConfig(),
getQuicConfig(&quic.Config{
EnableDatagrams: true,
Versions: []protocol.VersionNumber{version},
}),
)
Expect(err).ToNot(HaveOccurred())
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
Expect(conn.SendMessage([]byte{0})).To(HaveOccurred())
conn.CloseWithError(0, "")
<-time.After(10 * time.Millisecond)
})
})
}
})