diff --git a/internal/congestion/pacer.go b/internal/congestion/pacer.go index 037673611..89de50b1a 100644 --- a/internal/congestion/pacer.go +++ b/internal/congestion/pacer.go @@ -57,6 +57,7 @@ func (p *pacer) maxBurstSize() protocol.ByteCount { } // TimeUntilSend returns when the next packet should be sent. +// It returns the zero value of time.Time if a packet can be sent immediately. func (p *pacer) TimeUntilSend() time.Time { if p.budgetAtLastSent >= maxDatagramSize { return time.Time{} diff --git a/session.go b/session.go index a9252c72a..81147aab7 100644 --- a/session.go +++ b/session.go @@ -212,9 +212,10 @@ type session struct { } var ( - _ Session = &session{} - _ EarlySession = &session{} - _ streamSender = &session{} + _ Session = &session{} + _ EarlySession = &session{} + _ streamSender = &session{} + deadlineSendImmediately = time.Time{}.Add(42 * time.Millisecond) // any value > time.Time{} and before time.Now() is fine ) var newSession = func( @@ -1504,7 +1505,11 @@ func (s *session) sendPackets() error { } case ackhandler.SendAny: if s.handshakeComplete && !s.sentPacketHandler.HasPacingBudget() { - s.pacingDeadline = s.sentPacketHandler.TimeUntilSend() + deadline := s.sentPacketHandler.TimeUntilSend() + if deadline.IsZero() { + deadline = deadlineSendImmediately + } + s.pacingDeadline = deadline return nil } sent, err := s.sendPacket() diff --git a/session_test.go b/session_test.go index df4ecfa85..2b1538377 100644 --- a/session_test.go +++ b/session_test.go @@ -1379,7 +1379,25 @@ var _ = Describe("Session", func() { sess.run() }() sess.scheduleSending() - time.Sleep(50 * time.Millisecond) // make sure that only 2 packes are sent + time.Sleep(50 * time.Millisecond) // make sure that only 2 packets are sent + }) + + It("sends multiple packets, when the pacer allows immediate sending", func() { + sph.EXPECT().SentPacket(gomock.Any()) + sph.EXPECT().HasPacingBudget() + sph.EXPECT().HasPacingBudget().Return(true).AnyTimes() + sph.EXPECT().TimeUntilSend() // return the zero value of time.Time{} + sph.EXPECT().SendMode().Return(ackhandler.SendAny).Times(3) + packer.EXPECT().PackPacket().Return(getPacket(10), nil) + packer.EXPECT().PackPacket().Return(nil, nil) + mconn.EXPECT().Write(gomock.Any()) + go func() { + defer GinkgoRecover() + cryptoSetup.EXPECT().RunHandshake().MaxTimes(1) + sess.run() + }() + sess.scheduleSending() + time.Sleep(50 * time.Millisecond) // make sure that only 1 packet is sent }) // when becoming congestion limited, at some point the SendMode will change from SendAny to SendAck