Skip to content

Commit

Permalink
Make max datagram frame size configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
chungthuang authored and nmldiegues committed Feb 10, 2022
1 parent f3b0987 commit 5e2d522
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 17 deletions.
5 changes: 5 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func populateConfig(config *Config) *Config {
} else if maxIncomingUniStreams < 0 {
maxIncomingUniStreams = 0
}
maxDatagrameFrameSize := config.MaxDatagramFrameSize
if maxDatagrameFrameSize == 0 {
maxDatagrameFrameSize = int64(protocol.DefaultMaxDatagramFrameSize)
}

return &Config{
Versions: versions,
Expand All @@ -117,6 +121,7 @@ func populateConfig(config *Config) *Config {
StatelessResetKey: config.StatelessResetKey,
TokenStore: config.TokenStore,
EnableDatagrams: config.EnableDatagrams,
MaxDatagramFrameSize: maxDatagrameFrameSize,
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
DisableVersionNegotiationPackets: config.DisableVersionNegotiationPackets,
Tracer: config.Tracer,
Expand Down
2 changes: 2 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ var _ = Describe("Config", func() {
f.Set(reflect.ValueOf(true))
case "EnableDatagrams":
f.Set(reflect.ValueOf(true))
case "MaxDatagramFrameSize":
f.Set(reflect.ValueOf(int64(1280)))
case "DisableVersionNegotiationPackets":
f.Set(reflect.ValueOf(true))
case "DisablePathMTUDiscovery":
Expand Down
19 changes: 13 additions & 6 deletions datagram_queue.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package quic

import (
"fmt"

"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
Expand All @@ -15,7 +17,7 @@ type datagramQueue struct {

hasData func()

dequeued chan struct{}
dequeued chan error

logger utils.Logger
}
Expand All @@ -25,7 +27,7 @@ func newDatagramQueue(hasData func(), logger utils.Logger) *datagramQueue {
hasData: hasData,
sendQueue: make(chan *wire.DatagramFrame, 1),
rcvQueue: make(chan []byte, protocol.DatagramRcvQueueLen),
dequeued: make(chan struct{}),
dequeued: make(chan error),
closed: make(chan struct{}),
logger: logger,
}
Expand All @@ -42,18 +44,23 @@ func (h *datagramQueue) AddAndWait(f *wire.DatagramFrame) error {
}

select {
case <-h.dequeued:
return nil
case err := <-h.dequeued:
return err
case <-h.closed:
return h.closeErr
}
}

// Get dequeues a DATAGRAM frame for sending.
func (h *datagramQueue) Get() *wire.DatagramFrame {
func (h *datagramQueue) Get(maxDatagramSize protocol.ByteCount, version protocol.VersionNumber) *wire.DatagramFrame {
select {
case f := <-h.sendQueue:
h.dequeued <- struct{}{}
datagramSize := f.Length(version)
if datagramSize > maxDatagramSize {
h.dequeued <- fmt.Errorf("datagram size %d exceed current limit of %d", datagramSize, maxDatagramSize)
return nil
}
h.dequeued <- nil
return f
default:
return nil
Expand Down
7 changes: 4 additions & 3 deletions datagram_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package quic
import (
"errors"

"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"

Expand All @@ -23,7 +24,7 @@ var _ = Describe("Datagram Queue", func() {

Context("sending", func() {
It("returns nil when there's no datagram to send", func() {
Expect(queue.Get()).To(BeNil())
Expect(queue.Get(protocol.DefaultMaxDatagramFrameSize, protocol.Version1)).To(BeNil())
})

It("queues a datagram", func() {
Expand All @@ -36,11 +37,11 @@ var _ = Describe("Datagram Queue", func() {

Eventually(queued).Should(HaveLen(1))
Consistently(done).ShouldNot(BeClosed())
f := queue.Get()
f := queue.Get(protocol.DefaultMaxDatagramFrameSize, protocol.Version1)
Expect(f).ToNot(BeNil())
Expect(f.Data).To(Equal([]byte("foobar")))
Eventually(done).Should(BeClosed())
Expect(queue.Get()).To(BeNil())
Expect(queue.Get(protocol.DefaultMaxDatagramFrameSize, protocol.Version1)).To(BeNil())
})

It("closes", func() {
Expand Down
5 changes: 3 additions & 2 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ type Config struct {
DisableVersionNegotiationPackets bool
// See https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/.
// Datagrams will only be available when both peers enable datagram support.
EnableDatagrams bool
Tracer logging.Tracer
EnableDatagrams bool
MaxDatagramFrameSize int64
Tracer logging.Tracer
}

// ConnectionState records basic details about a QUIC connection
Expand Down
4 changes: 2 additions & 2 deletions internal/protocol/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ const MaxPostHandshakeCryptoFrameSize = 1000
// but must ensure that a maximum size ACK frame fits into one packet.
const MaxAckFrameSize ByteCount = 1000

// MaxDatagramFrameSize is the maximum size of a DATAGRAM frame as defined in
// DefaultMaxDatagramFrameSize is the maximum size of a DATAGRAM frame as defined in
// https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
const MaxDatagramFrameSize ByteCount = 1220
const DefaultMaxDatagramFrameSize ByteCount = 1220

// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames.
// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
Expand Down
2 changes: 1 addition & 1 deletion packet_packer.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, ackAll

var hasDatagram bool
if p.datagramQueue != nil {
if datagram := p.datagramQueue.Get(); datagram != nil {
if datagram := p.datagramQueue.Get(maxFrameSize, p.version); datagram != nil {
payload.frames = append(payload.frames, ackhandler.Frame{
Frame: datagram,
// set it to a no-op. Then we won't set the default callback, which would retransmit the frame.
Expand Down
9 changes: 6 additions & 3 deletions session.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ var newSession = func(
RetrySourceConnectionID: retrySrcConnID,
}
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
params.MaxDatagramFrameSize = protocol.ByteCount(s.config.MaxDatagramFrameSize)
if params.MaxDatagramFrameSize == 0 {
params.MaxDatagramFrameSize = protocol.DefaultMaxDatagramFrameSize
}
}
if s.tracer != nil {
s.tracer.SentTransportParameters(params)
Expand Down Expand Up @@ -440,7 +443,7 @@ var newClientSession = func(
InitialSourceConnectionID: srcConnID,
}
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
params.MaxDatagramFrameSize = protocol.ByteCount(s.config.MaxDatagramFrameSize)
}
if s.tracer != nil {
s.tracer.SentTransportParameters(params)
Expand Down Expand Up @@ -1415,7 +1418,7 @@ func (s *session) handleAckFrame(frame *wire.AckFrame, encLevel protocol.Encrypt
}

func (s *session) handleDatagramFrame(f *wire.DatagramFrame) error {
if f.Length(s.version) > protocol.MaxDatagramFrameSize {
if f.Length(s.version) > protocol.ByteCount(s.config.MaxDatagramFrameSize) {
return &qerr.TransportError{
ErrorCode: qerr.ProtocolViolation,
ErrorMessage: "DATAGRAM frame too large",
Expand Down

0 comments on commit 5e2d522

Please sign in to comment.